Использование указателей для связи между функциями

Использование указателей для связи между функциями

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

/* обмен3 */                                            

main( )

{

int x = 5, у = 10;

printf(" Вначале x = %d и у = %d. " , x, у);

interchange(&x,&y); /* передача адресов функции */

printf(" Теперь x = %d и у = %d. ", x, у);

}

interchange(u, v)

int *u, *v; /* u и v являются указателями */

{

int temp; 

temp = *u; /* temp присваивается значение, на которое указывает u */

*u = *v;

*v = temp;

}

После всех встретившихся трудностей, проверим, работает ли этот вариант 1

Вначале x = 5 и y = 10.

Теперь x = 10 и y = 5.

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

interchange(&x, &y);

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

interchange(u,v)

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

int *u, *v;

Далее в теле функции оператор описания:

int temp;

используется с целью резервирования памяти. Мы хотим поместить значение переменной х в переменную temp, поэтому пишем:

temp = *u;

Вспомните, что значение переменной u - это , поэтому переменная u ссылается на х. Это означает, что операция *u дает значение x, которое как раз нам и требуется. Мы не должны писать, например, так:

temp = u; /* неправильно */

поскольку при этом происходит запоминание адреса переменной х, а не ее значения; мы же пытаемся осуществить обмен значениями, а не адресами.

     Точно так же, желая присвоить переменной у значение переменной х, мы пользуемся оператором:

*u = *v;

который соответствует оператору

x = y;

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

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

function1(х);

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

function2(&x);

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

functionl(num)

int num;

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

function2(ptr)

int *ptr;

     Пользуйтесь первой формой, если входное значение необходимо функции для некоторых вычислений или действий, и второй формой, если функция должна будет изменять значения переменных в вызывающей программе. Вторая форма вызова уже применялась при обращении к функции scanf( ). Когда мы хотим ввести некоторое значение в переменную num, мы пишем scanf("%d, &num). Данная функция читает величину, затем, используя адрес, который ей дается, помещает эту величину в память.

     Указатели позволяют обойти тот факт, что переменные функции interchange( ) являются локальными. Они дают возможность нашей функции "добраться" до функции main( ) и изменить величины описанных в ней объектов.

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