Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Задание на лабораторную работу № 4




 

Название работы: Файлы и работа с ними в С и С++.

Цель работы: Изучить файловые операции, используемые в С и С++. Приобрести навыки ввода/вывода информации в файлы.

 

1. Составить программу, осуществляющую поиск в заданном файле заданной строки символов и замену ее на другую строку символов той же длины.

2. По справочной системе исследовать функции работы с файлами.

 

Контрольные вопросы:

 

1. Понятие файла.

2. Открытие файла и закрытие файла.

3. Форматный ввод-вывод данных в файл.

4. Назовите стандартные потоки ввода/вывода, которые автоматически открывает язык С.

5. Чтение запись с произвольным доступом.

6. Приведите примеры функций для работы с файлами.


Лабораторная работа № 5
Функции



Теоретическая часть

Общие сведения.

Программы на языке С обычно состоят из большого числа отдельных функций (подпрограмм). Функции могут находиться как в одном, так и в нескольких файлах.

В языке запрещено определять одну функцию внутри другой. Связь между функциями осуществляется- через аргументы, возвращаемые значения и внешние переменные. Передача значения из вызванной функции в вызвавшую происходит с помощью оператора возврата, который записывается в следующем формальном виде:

return выражение;

Таких операторов в подпрограмме может быть несколько и тогда они фиксируют соответствующие точки выхода. Вызвавшая функция может при необходимости игнорировать возвращаемое значение. После слова return можно ничего не записывать: в этом случае вызвавшей функции никакого значения не передается. Управление передается вызвавшей функции и в случае выхода «по концу» (последняя закрывающаяся фигурная скобка).

В языке С аргументы функции передаются по значению, т. е. вызванная функция получает свою временную копию каждого аргумента, а не его адрес. Это означает, что функция не может изменять сам оригинальный аргумент в вызвавшей ее программе. Ниже будет показано, как убрать это ограничение. Если же в качестве аргумента функции используется имя массива, то передается начало массива (адрес начала массива), а сами элементы не копируются. Функция может изменять элементы массива, сдвигаясь (индексированием) от его начала.

Рассмотрим, как соответствуют друг другу параметры в, вызове и в списке функции. Пусть вызывающая программа обращается к функции следующим образом:

а = fun (b, с);

Здесь b и с - аргументы, значения которых передаются в вызываемую подпрограмму. Если описание функции начинается так:

void fun (int b, int с)

то имена передаваемых аргументов в вызове и в программе fun будут одинаковыми. Если же описание функции начинается, например, строкой

void fun (int i, int j)

то вместо имени b в вызвавшей функции для того же аргумента в функции fun будет использовано имя i, а вместо c-j. Пусть обращение к функции имеет вид

а = fun ( &b, &c);

Здесь подпрограмме передаются адреса переменных b и с. Поэтому прототип функции должен быть, например, таким:

void fun (int *k, int *с)

Теперь k получает адрес передаваемой переменной b, а с - адрес передаваемой переменной с. В результате в вызвавшей программе с - это переменная целого типа, а в вызванной программе с - это указатель на переменную целого типа. Если в вызове записаны те же имена, что и в списке параметров, но они записаны в другом порядке, то все равно устанавливается соответствие между i-м именем в списке и i-м именем в вызове.

Выше уже указывалось, что переменные передаются функции по значению, поэтому нет прямого способа в вызванной функции изменить некоторую переменную в вызвавшей функции. Однако это легко сделать, если передавать в функцию не переменные, а их адреса.

Рассмотрим, как функции можно передать массив в виде параметра. Здесь возможны три варианта:

1. Параметр задается как массив (например: int m[100]).

2. Параметр задается как массив без указания его размерности (например: int m[]).

3. Параметр задается как указатель (например: int *m). Этот вариант используется наиболее часто.

Независимо от выбранного варианта вызванной функции передается указатель на начало массива. Сами же элементы массива не копируются.

Если некоторые переменные, константы, массивы, структуры объявлены как глобальные, то их не надо включать в список параметров вызванной функции. Она все равно получит к ним доступ.

Функции в языке С необходимо объявлять. В книге будем использовать уже рассмотренные ранее конструкции, называемые прототипом. В соответствующем объявлении будет дана информация о параметрах. Она представляется в следующем виде:

тип функция (параметр_1, параметр_2,...);

Для каждого параметра можно указать только его тип (например: тип функция (int. float, ...);), а можно дать и его имя (например: тип функция (int а, float b,...);). В языке С разрешается создавать функции с переменным числом параметров. Тогда при задании прототипа вместо последнего из них указывается многоточие.

Классы памяти.

В языке С различают четыре основных класса памяти: внешнюю (глобальную), автоматическую (локальную), статическую и регистровую.

Внешние переменные определены вне функций и, следовательно, доступны для любой из них. Они могут объявляться только один раз. Язык не позволяет определять одни функции внутри других. Область видимости внешней переменной простирается от точки во входном файле, где она объявлена, до конца файла. Если на внешнюю переменную нужно ссылаться до ее объявления или она определена в другом входном файле, то вступает в силу описание extern.

Автоматические переменные по отношению к функциям являются внутренними или локальными. Они начинают существовать при входе в функцию и уничтожаются при выходе из нее (для них можно использовать либо нет ключевое слово auto).

Статические переменные объявляются с помощью ключевого слова static. Они могут быть внутренними (локальными) или внешними (глобальными). Внутренние Статические переменные, как и автоматические, локальны по отношению к отдельной функции. Однако они продолжают существовать, а не возникают и уничтожаются при каждом ее вызове. Другими словами, они являются собственной постоянной памятью для функции. Внешние статические переменные доступны внутри оставшейся части файла после того, как они в нем объявлены, однако в других файлах они неизвестны. Это, в частности, позволяет скрыть данные одного файла от другого файла.

Регистровые переменные относятся к последнему классу. Ключевое слово register говорит о том, что переменная, о которой идет речь, будет интенсивно использоваться. Если возможно, значения таких переменных помещаются во внутренние регистры микропроцессора (Borland C++ использует для этих целей регистры SI и DI), что может. привести к более быстрой и короткой программе. Для регистровых переменных нельзя взять адрес; они могут быть только автоматическими с допустимыми типами int или char.

Таким образом, можно выделить четыре спецификатора класса памяти: extern, auto, static, register. Они используются в следующей общей форме:

спецификатор_класса_памяти тип список_переменных;

Выше уже говорилось об инициализации, т. е. о присвоении различным объектам начальных значений. Если явная инициализация отсутствует, гарантируется, что внешние и статические переменные будут иметь значение нуль, а автоматическое и регистровые - неопределенное значение.

Указатели на функции.

В языке С сама функция не может быть значением переменной, но можно определить указатель на функцию. С ним уже можно обращаться как с переменной: передавать его другим функциям, помещать в массивы и т. п.

Код функции в компьютере занимает физическую память. В этой памяти есть точка входа, которая используется для того, чтобы войти в функцию и запустить ее на выполнение. Указатель на функцию как раз и адресует эту точку входа. Это уже будет обычная переменная и с ним можно делать все, что можно делать с переменной. Однако через указатель можно Войти в функцию, т. е. запустить ее на выполнение. Объявление вида:

int (*f) ();

говорит о том, что f-это указатель на функцию, возвращающую целое значение. Первая пара скобок необходима, без них int *f(); означало бы, что f - функция, возвращающая указатель на целое значение. После объявления указателя на функцию в программе можно использовать объекты: *f-сама функция; f - указатель на функцию, Здесь имеется некоторая аналогия с массивами. Для любой функции ее имя (без скобок и аргументов) является указателем на эту функцию.

Рекурсия.

Рекурсией называется такой способ вызова, когда функция обращается к самой себе. Важным моментом при составлении рекурсивной программы является организация выхода. Здесь легко допустить ошибку, заключающуюся в том, что функция будет последовательно вызывать саму себя бесконечно долго. Поэтому рекурсивный процесс должен шаг за шагом так упрощать задачу, чтобы в конце концов для нее появилось не рекурсивное решение.

Перегрузка функций в файле (только С++)

Перегрузка функций применяется для приведения поведения программы в соответствии с ее типами данных. Преимущество использования перегрузки для программиста состоит в том, что ему достаточно указать только одно имя функции, а компилятор сам возьмет на себя задачу контроля типа параметров и вызова правильной версии функции.

Пример

int max(int a, int b){

return (a > b ? a:b);

}

char* max(const char*s1, const char* s2){

return (strcmp(s1,s2) ? s1:s2);

}

int max(int a, char* s){

return (a > strlen(s) ? a : strlen(s));

}

 

Перегружаемые функции должны находиться в одной области определения, иначе произойдет не перегрузка, а сокрытие.

Не могут перегружаться функции, имеющие совпадающие типы и число аргументов, но разные типы возвращаемых значений.

Не могут перегружаться функции, имеющие неявно совпадающие типы аргументов, например int и int&.

 

Примеры программ

Пример1. Получение адреса числа, объяснение того, что в функции передаются копии значений

#include<stdio.h>

#include<conio.h>

void mikado(int bah)

{

int pooh = 10;

printf("B mikado(), pooh = %d и &pooh = %u\n", pooh,&pooh);

printf("В mikado(), bah = %d и &bah = %u", bah, &bah);

}

void main(void)

{

int pooh = 2, bah = 5;

void mikado(int bah);

 

clrscr();

printf("В main(), pooh =%d и &pooh = %u\n", pooh, &pooh);

printf("В main(), bah = %d и &bah = %u\n", bah, &bah);

mikado(pooh);

getch();

}

Пример2. Обмен значений переменных

#include <stdio.h>

#include <conio.h>

int interchange (int *u, int *v);

void main (void)

{

int x=5,y=10;

clrscr();

printf("В начале x=%d и &x=%u, y=%d и &y=%u\n",x,&x,y,&y);

interchange(&x,&y);

printf("Теперь x=%d, y=%d\n",x,y);

}

 

interchange (int *u,int *v)

{

int temp;

temp =*u;

*u=*v;

*v=temp;

return (0);

}










Последнее изменение этой страницы: 2018-05-10; просмотров: 145.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...