Язык Си - руководство для начинающих
Шрифт:
return(u);
и изменить форму вызова в функции main следующим образом:
х = interchange(x, у);
В результате такого обращения к функции переменная х получит новое значение, но у при этом не изменится.
С помощью оператора return в вызывающую программу можно передать только одну величину. Но нам нужно передать две величины. Это оказывается вполне осуществимым! Для этого нужно лишь воспользоваться "указателями".
Указатели:
Указатели? Что это такое? Вообще говоря, указатель - некоторое символическое представление адреса. Например, ранее мы воспользовались операцией получения адреса для нахождения адреса переменной pooh. В данном случае &pooh означает "указатель на переменную pooh". Фактический адрес - это число (в нашем случае 56002), а символическое представление адреса &pooh является константой типа указатель. После всего сказанного выше становится очевидным, что адрес ячейки, отводимой переменной pooh, в процессе выполнения программы не меняется.
В языке Си имеются и переменные типа указатель. Точно так же как значением переменной типа char является символ, а значением переменной типа int– целое число, значением переменной типа указатель служит адрес некоторой величины. Если мы дадим указателю имя ptr, то сможем написать, например, такой оператор
ptr = &pooh; /* присваивает адрес pooh переменной ptr */
Мы говорим в этом случае, что ptr "указывает на" pooh. Различие между двумя формами записи: ptr и &pooh, заключается в том, что ptr– это переменная, в то время как &pooh– константа. В случае необходимости мы можем сделать так, чтобы переменная ptr указывала на какой-нибудь другой объект:
ptr = &bah; /* ptr указывает на bah, а не на pooh */
Теперь значением переменной ptr является адрес переменной bah.
Операция косвенной адресации: *
Предположим, мы знаем, что в переменной ptr содержится ссылка на переменную bah. Тогда для доступа к значению этой переменной можно воспользоваться операцией "косвенной адресации" (*). (Не путайте эту унарную операцию косвенной адресации с бинарной операцией умножения *).
val = *ptr; /* определение значения, на которое указывает ptr */
Последние два оператора, взятые вместе, эквивалентны следующему:
val = bah;
Использование операций получения адреса и косвенной адресации оказывается далеко не прямым путем к результату; отсюда и появление слова "косвенная" в названии операции.
Резюме: операции, связанные с указателями
I. Операция получения адреса &
Когда за этим знаком следует имя переменной, результатом операции является адрес указанной переменной.
Пример:
&nurse дает адрес переменной nurse.
II. Операция косвенной адресации
* Когда за этим таком следует
указатель на переменную, результатом операции является величнна, помещенная и ячейку с указанным адресом.Пример:
nurse = 22;pir = &nurse; /* указатель на nurse */ val = *ptr;
Результатом выполнения этого фрагмента является присваивание значения 22 переменной val.
Описание указателей
Мы знаем, как описывать переменные типа int и других типов. Но как описать переменную типа "указатель"? На первый взгляд это можно сделать так:
pointer ptr; /* неправильный способ описания указателя */
Почему нельзя использовать такую запись? Потому что недостаточно сказать, что некоторая переменная является указателем. Кроме этого, необходимо сообщить еще, на переменную какого типа ссылается данный указатель! Причина заключается в том, что переменные разных типов занимают различное число ячеек, в то время как для некоторых операций, связанных с указателями, требуется знать объем отведенной памяти. Ниже приводятся примеры правильного описания указателей:
int *pi; /* указатель на переменную типа целого */
char *рс; /* указатель на символьную переменную */
float *pf, *pg; /* указатели на переменные с плавающей точкой */
Спецификация типа задает тип переменной, на которую ссылается указатель, а символ звездочка (*) определяет саму переменную как указатель. Описание вида int *pi; говорит, что pi– это указатель и что *pi– величина типа int.
РИС. 9.5. Описание и использование указателей.
Точно так же величина (*рс), на которую ссылается переменна рс, имеет тип char. Что можно сказать о самой переменной рс? Мы считаем, что она имеет тип "указатель на переменную типа char". Ее величина, являющаяся адресом,- это целое число без знака, поэтому при выводе на печать значения переменной рс мы будем пользоваться форматом %u.
Использование указателей для связи между функциями
Мы только прикоснулись к обширному и увлекательному миру указателей. Сейчас нашей целью является использование указателей для решения задачи об установлении связи между функциями. Ниже приводится программа, в которой указатели служат средством, обеспечивающим правильную работу функции, которая осуществляет обмен значениями переменных. Посмотрим, как она выглядит, выполним ее, а затем попытаемся понять, как она работает.
/* обмен3 */
main
{
int x = 5, у = 10;
printf(" Вначале x = %d и у = %d.\n" , x, у);
interchange(&x,&y); /* передача адресов функции */
printf(" Теперь x = %d и у = %d.\n", x, у);
}
interchange(u, v)