Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Передача массивов в качестве параметров.




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

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

Функция – именованная последовательность описаний и операторов, выполняющая какое-либо законченное действие. Принимает параметры и возвращает значения. Объявляется несколько раз, определяется один.

Пользовательская функция – это функция, которая создана пользователем.

Прототип функции (объявление) – задает имя функции, тип возвращаемого значения и список передаваемых параметров. Формат прототипа:

<класс памяти> <тип>имя (список формальных параметров); (класс памяти auto, static)

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

Таким образом, прототип – это явное объявление функции, которое предшествует определению функции. Тип возвращаемого значения при объявлении функции должен соответствовать типу возвращаемого значения в определении функции. Хороший стиль программирования требует задания прототипа во всех случаях.

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

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

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

[ класс ] тип имя ([ список_параметров]) [ throw (исключения) ]

{ тело функции }

Составные части определения:

1) Используя ключевые слова extern (во всех модулях программы), static (в пределах модуля, в котором определена функция) задается область видимости функции;

2) Тип возвращаемого значения - любой, кроме массива или функции (возможен указатель на массив или функцию) + void.

3) Исключения.

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

Тип возвращаемого значения и типы параметров совместно определяют тип функции.

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

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

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

Возвращаемое значение.

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

Функция возвращает значение, если ее выполнение заканчивается оператором return, содержащим некоторое выражение. Результат возвращается в точку вызова функции.

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

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

Передача параметров в функцию может осуществляться по значению и по адресу.

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

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

типимя_функции (const тип_переменной* имя_переменной, …)

Передача массивов в качестве параметров.

При использовании в качестве параметра массива в функцию передается указатель на его первый элемент, иными словами, массив всегда передается по адресу. При этом, информация о количестве элементов массива теряется, и следует передавать его размерность через отдельный параметр: int sum(const int* mas, const int n).

При передаче многомерных массивов все размерности, если они не известны на этапе компиляции, должны передаваться в качестве параметров. Внутри функции массив интерпретируется как одномерный, а его индекс пересчитывается в программе: int sum(const int *a, const int nstr, const int nstb).

Для того, чтобы работать с двумерным массивом естественным образом, можно применить альтернативный способ выделения памяти:

int sum(int **a,const int nstr,const int nstb);

где **a – указатель на 1-ый элемент, nstr и nstb – количество строк и столбцов соответственно

Структурные переменные в качестве аргументов.

Существует три способа передачи структур функциям:

- передача компонентов структуры по частям;

- передача целиком структуры;

- передача указателя на структуру.

Например, в функцию передаются координаты двух точек:

void showrect(struct point p1,struct point p2)

{

printf("Левый верхний угол прямоугольника:%d %d\n",

p1.x, p1.y);

printf("Правый нижний угол прямоугольника:

%d %d\n", p2.x, p2.y);

}

При вызове такой функции ей надо передать две структуры:

struct point pt1={5,5},

pt2={50,50};

showrect(pt1,pt2);

Теперь рассмотрим функцию, возвращающую структуру:

struct point makepoint (int x,int y) /*makepoint – формирует точку по компонентам x и y*/

{

struct point temp;

temp.x = x;

temp.y = y;

return temp;

}

Результат работы этой функции может быть сохранен в специальной переменной и выведен на экран:

struct point buf;

buf=makepoint(10,40);

printf("%d %d\n",buf.x,buf.y);

После выполнения этого фрагмента на экран будут выведены два числа: 10 и 40.

Указатели на структуру

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

Формат: struct point *pp;

где pp – указатель на структуру типа struct point, *pp – сама структура, (*pp).x и (*pp).y – члены структуры.

Скобки (*pp).x необходимы, так как приоритет операции (.) выше приоритета операции (*). В случае отсутствия скобок *pp.x понимается как *(pp.x).

Инициализация указателя на структуру выполняется так же, как и инициализация указателей других типов: struct point var1, *S1; здесь var1 – структурная переменная, *S1 – указатель на структуру.

Для определения значения указателя ему нужно присвоить адрес уже сформированной структуры:

S1 = &var1;

Теперь возможно еще одно обращение к элементам структуры:

(*S1).name.

Указатели на структуры используются весьма часто, поэтому для доступа к ее полям была введена короткая форма записи. Если р – указатель на структуру, то p →<поле структуры> позволяет обратиться к указанному полю структурной переменной.

Знак → (стрелка) вводится с клавиатуры с помощью двух символов: '–' (минус) и '>' (больше). Например, pp → x; pp → y.

Операторы доступа к полям структуры (.) и (→) вместе с операторами вызова функции () и индексами массива [] занимают самое высокое положение в иерархии приоритетов операций в языке C.

Указатели на структуру используются в следующих случаях:

· доступ к структурам, размещенным в динамической памяти;

· создание сложных структур данных – списков, деревьев;

· передача структур в качестве параметров в функции.


Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...