Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Указатели: первое знакомство
Что собой представляют указатели? По существу указатель — это переменная (или в общем случае объект данных), значением которой является адрес в памяти. Подобно тому, как переменная char имеет в качестве значения символ, а переменная int — целое число, переменная тина указателя содержит значение адреса. С указателями связаны многочисленные применения в языке С; в данной главе вы увидите, как и почему они применяются как параметры функций.
Если назначить переменной типа указателя имя ptr, можно записывать операторы вроде показанного ниже:
ptr = &pooh; // присваивает переменной ptr адрес переменной pooh
Мы говорим, что ptr “указывает на” pooh. Разница между ptr и &pooh состоит в том, что ptr является переменной, a &pooh — константой. Иначе говоря, ptr — это модифицируемое 1-значение, a &pooh — r-значение. При желании можно сделать так, чтобы переменная ptr указывала на что-то другое:
ptr = &bah; // переменная ptr указывает на bah вместо pooh
Теперь значением ptr будет адрес bah.
Чтобы создать переменную-указатель, вы должны иметь возможность объявить ее тип. Предположим, что вы хотите объявить переменную ptr так, чтобы она могла хранить адрес значения int. Для такого объявления необходимо использовать новую операцию, которую мы рассмотрим в следующем разделе.
Операция разыменования: *
Предположим, вам известно, что ptr указывает на bah:
ptr = &bah;
Тогда для выяснения значения, хранящегося в переменной bah, можно применить операцию разыменования * (которая также называется операцией снятия косвенности)’, не путайте эту унарную операцию с бинарной операцией умножения * (тот же символ, но другой синтаксис):
val = *ptr; // выяснение значения, на которое указывает ptr
Операторы ptr = &bah; и val = *ptr; вместе эквивалентны следующему оператору:
val = bah;
Использование операций взятия адреса и снятия косвенности — это косвенный путь достижения нужного результата, откуда и происходит название “операция снятия косвенности”.
358 глава 9
Сводка: операции, связанные с указателями Операция взятия адреса
&
Общий комментарий
Символ &, за которым следует имя переменной, предоставляет адрес этой переменной. Пример
&nurse является адресом переменной nurse.
Операция разыменования
*
Общий комментарий
Символ *, за которым следует имя указателя или адрес, предоставляет значение, которое хранится по указанному адресу.
Пример
nurse = 22;
ptr = &nurse; // указатель на nurse
val = *ptr; // присваивает val значение, хранящееся в ячейке ptr
В конечном итоге переменная val получает значение 22.
Объявление указателей
Вы уже знаете, как объявлять переменные int и других фундаментальных типов. А как объявить переменную типа указателя? Можно было бы предположить, что объявление выглядит примерно так:
pointer ptr; // указатель не объявляется подобным образом
Почему это не подойдет? Дело в том, что объявления переменной указателем далеко не достаточно. Должен быть также задан вид переменной, на которую указывает указатель. Причина в том, что разные типы переменных занимают разные объемы памяти, а некоторые операции с указателями требуют знания этих размеров памяти. Кроме того, программе должно быть известно, данные какого вида хранятся по конкретному адресу. Типы long и float могут занимать один и тот же объем памяти, но хранят числа они по-разному. Ниже демонстрируются случаи объявления указателей:
int * pi; // pi - указатель на целочисленную переменную
char * рс; // рс - указатель на символьную переменную
float * pf, * pg; // pf, pg - указатели на переменные с плавающей запятой
Спецификация типа идентифицирует тип переменной, на которую указывает указатель, а звездочка (*) — что переменная сама является указателем. Объявление int * pi; говорит о том, что pi является указателем, и *pi имеет тип int (рис. 9.5).
Пробел между символом * и именем указателя необязателен. Часто программисты применяют пробел в объявлении и опускают его при разыменовании переменной.
Значение (*рс), на которое указывает указатель рс, имеет тип char. А что собой представляет собственно рс? Мы описываем его как имеющий тип “указатель на char”. Значение рс — э го адрес, и в большинстве систем он внутренне представлен как целое число без знака. Однако вы не должны считать, что указатель относится к целочисленному типу. Есть действия, которые можно выполнять над целыми числами, но нельзя - над указателями, и наоборот.
Функции 359
Рис. 9.5. Объявление и использование указателей
Например, целые числа можно умножать, но делать это в отношении указателей не допускается. Таким образом, указатель в действительности представляет собой новый тип, а не целочисленный. По этой причине, как упоминалось ранее, в ANSI С специально для указателей предусмотрена форма %р.
Использование указателей для обмена данными между функциями
Мы лишь слегка коснулись многообразного и удивительного мира указателей, но нас интересует применение указателей для решения задачи обмена данными. В листинге 9.15 представлена программа, в которой с помощью указателей обеспечивается работа функции interchange(). Давайте рассмотрим код, запустим ее и выясним, как она рабо тает.
Листинг 9.15. Программа swap3.c
360 Глава 9
Заработает ли программа из листинга 9.15 после компиляции?
Первоначально х = 5 и у = 10.
Теперь х = 10 и у = 5.
Да, она работает.
Давайте теперь проанализируем код из листинга 9.15. Прежде всего, вызов функции выглядит так:
interchange (&х, &у);
Вместо передачи значений х и у функция передаются их адреса. Это означает, что формальные аргументы и и v, указанные в прототипе и определении функции interchange(), в качестве своих значений будут содержать адреса. Следовательно, они должны быть объявлены как указатели. Поскольку х и у являются целочисленными, а и и v — указателями на целочисленные значения, они объявляются следующим образом:
void interchange (int * u, int * v)
Далее в теле функции содержится объявление, которое предоставляет область памяти, необходимую для временного хранения:
int temp;
Для сохранения значения х в temp используется оператор
temp = *u;
Вспомните, что и имеет значение &х, поэтому и указывает на х. Это означает, что *и дает значение х, что и требовалось. Не следует записывать
temp = и; /* Неправильно */
поскольку в этом случае переменной temp присваивается адрес переменной х вместо ее значения, а задача состоит в том, чтобы осуществить обмен значениями, но не адресами.
Аналогично, чтобы присвоить переменной х значение переменной у, применяйте оператор
Читать дальшеИнтервал:
Закладка: