Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЗФ_ОАиП / Лекции ГГУ Скорины - Программирование.doc
Скачиваний:
179
Добавлен:
21.03.2016
Размер:
2.27 Mб
Скачать

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

19.1. Способы передачи параметров в функции

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

В языках программирования имеется два основных способа передачи параметров подпрограмме. Первый из них – передача по значению. При его применении в формальный параметр подпрограммы копируется значение фактического параметра (аргумента). В таком случае изменения формального параметра на фактический аргумент не влияют.

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

В языке С есть только один способ сопоставления фактических и формальных параметров – передача по значению (передачи параметров по ссылке есть в С++). В Паскале есть передача по значенияю и по ссылке. Бывают и другие методы (в Fortran – копирование-восстановление, в Algol – передача по имени).

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

Метод передачи по значению реализуется следующим способом:

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

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

19.2. Передача параметров в функции в языке с

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

void f(int k) { k = -k; } void main() {   int i = 1;   f(i);   printf("i = %d\n", i); // результат: i = 1 }

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

19.3. Передача указателей в функции

А что делать, если функция должна изменить значение фактического параметра? Самый очевидный, но не самый лучший, способ – заменить такой параметр глобальной переменной. Минус – повышение шансов ошибиться из-за неучтенных побочных эффектов при вызове функций.

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

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

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

Задача. Написать функцию для замены местами значений двух переменных и вызвать ее из функции main().

void swap(int *pa, int *pb) { // параметры-указатели

int temp;

temp = *pa; // сохранить значение a

*pa = *pb; // занести b в a

*pb = temp; // занести a в b

}

void main(void) {

int i = 10, j = 20;

printf("i и j перед обменом значениями: %d %d\n", i, j);

swap(&i, &j); // передаем адреса переменных i и j

printf("i и j после обмена значениями: %d %d\n", i, j);

}

Функция swap() может выполнять обмен значениями двух переменных, на которые указывают pa и pb, потому что в функцию передаются адреса переменных, а не их значения. Внутри функции, используя стандартные операции с указателями, можно получить доступ к содержимому переменных и провести обмен их значений.

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

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

void main(void) {

int i = 10, j = 20;

int *pi = &i, *pj = &j;

printf("i и j перед обменом значениями: %d %d\n", i, j);

swap(pi, pj); // передаем адреса переменных i и j

printf("i и j после обмена значениями: %d %d\n", i, j);

}

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

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

Задача. Написать две функции для вычисления суммы двух отрицательных чисел и их вызов из функции main(). Исходные данные должны вводиться в функции main(). Первая функция должна возвращать заданную величину. Во второй функции обеспечить контроль правильности исходных данных. Функция, кроме вычисления заданной величины, должна возвращать признак правильности исходных данных.

int sum1(int a, int b) {

return a+b;

}

int sum2(int a, int b, int *sum) {

if (a >= 0 || b >= 0)

return 0; // признак неверных данных

*sum = a + b;

return 1; // признак правильных данных

}

void main(void) {

int x, y, s;

scanf(“%d %d”, &x, &y);

printf("Сумма 1 = %d\n", sum1(x,y));

if (sum2(x,y,&s) == 1)

printf("Сумма 2 = %d\n", s);

else

printf("Неверные данные!\n");

}