Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Обычно программа применяет разные области памяти для статических объектов, автоматических объектов и динамически выделенных объектов. Сказанное демонстрируется в листинге 12.15.
Листинг 12.15. Программа where.с
Ниже показан вывод, полученный в одной из систем:
static_store: 30 по адресу 00378000
auto_store: 40 по адресу 0049FB8C
*pi: 35 по адресу 008Е9ВА0
Строковый литерал по адресу 00375858
Автоматический массив char по адресу 0049FB74 Динамическая строка по адресу 008E9BD0 Строка в кавычках по адресу 00375908
Как видите, статические данные, включая строковые литералы, занимают одну область, автоматические данные — вторую область, а динамически выделенные данные — третью область (часто называемую кучей или свободным хранилищем).
Классы хранения, связывание и управление памятью 517
Квалификаторы типов ANSI С
Вам уже известно, что переменная характеризуется типом и классом хранения. В стандарте С90 были добавлены еще два свойства: постоянство и изменчивость. Эти свойства объявляются с помощью ключевых слов const и volatile, которые создают квалифицированные типы. В стандарте С99 появился третий квалификатор, restrict, предназначенный для содействия компилятору в оптимизации. Наконец, в СИ добавлен четвертый квалификатор, _Atomic. Стандарт С11 предоставляет дополнительную библиотеку, управляемую stdatomic.h, для поддержки параллельного программиро- ванпя, и Atomic является частью этой необязательной поддержки.
Стандарт С99 наделяет квалификаторы типов новым свойством — теперь они идем- потеитиы. Хотя это звучит подобно жесткому требованию, в действительности это означает лишь то, что один и гот же квалификатор можно указывать в объявлении более одного раза, и избыточные квалификаторы игнорируются:
const const const int n = 6; //то же самое, что и const int n = 6;
Это делает приемлемой, например, следующую последовательность:
typedef const int zip;
const zip q = 8;
Квалификатор типа const
Вы уже встречались со случаями использования const в главах 4 и 10. В качестве напоминания: ключевое слово const в объявлении создает переменную, значение которой не может быть изменено посредством присваивания либо инкрементирования/ декрементирования. В случае компилятора, совместимого со стандартом ANSI, код
const int nochange; /* указывает, что m является константой */
nochange =12; /* не разрешено */
приводит к выдаче сообщения об ошибке. Тем не менее, инициализировать переменную const можно. Таким образом, следующий код допустим:
const int nochange = 12; /* все в порядке */
Предыдущее объявление делает nochange переменной только для чтения. После того, как она инициализирована, изменять ее нельзя.
Ключевое слово const можно применять, например, для создания массива данных, которые в программе не могут изменяться:
const int days 1 [12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Использование const с объявлениями указателей и параметров
Применять ключевое слово const при объявлении простой переменной и массива довольно просто. Указатели в этом смысле сложнее, т.к. необходимо проводить различие между объявлением самого указателя как const и превращением в const значения, на которое он указывает. Объявление
const float * pf; /* pf указывает на константное значение float */
создает указатель pf, ссылающийся на значение, которое должно оставаться постоянным. Значение самого pf можно изменять. Например, его можно установить для указания на другое значение const. В противоположность этому, объявление
float * const pt; /* pt является указателем const */ говорит о том, что значение самого указателя pt не может быть модифицировано.
518 глава 12
Он должен всегда ссылаться на один и то же адрес, однако значение, на которое он указывает, может изменяться. Наконец, объявление
const float * const ptr;
означает, что ptr должен всегда указывать па одну и ту же ячейку, а значение, хранящееся в этой ячейке, не должно изменяться.
Существует и третье место, куда можно поместить const:
float const * pfc; // то же, что и const float * pfc;
Как отражает коммен тарий, помещение const после имени типа и перед символом * означает что указатель не может использоваться для изменения значения, па которое он ссылается. Выражаясь кратко, ключевое слово const, находящееся где угодно слева от символа *, делает константными данные, а справа — делает константным сам указатель.
Распространенным использованием этого нового ключевого слова является объявление указателей, которые служат формальными параметрами функций. Например, пусть имеется функция по имени display() , которая отображает содержимое массива. Чтобы применить данную функцию, необходимо передать ей в качестве фактического аргумента имя массива, но имя массива одновременно представляет собой и его адрес. Это позволит функции изменять данные из вызывающей функции. Однако следующий прототип предотвращает такое изменение:
void display(const int array[], int limit);
В прототипе и в заголовке функции объявление параметра const int array[] аналогично объявлению const int * array, и первое объявление говорит о том, что данные, на которые указывает array, не могут быть изменены.
Этой практики придерживается библиотека ANSI С. Если указатель используется только для предоставления функции доступа к значениям, он объявляется как указатель на квалифицированный посредством const тип. Если указатель применяется для изменения данных в вызывающей функции, то ключевое слово const не используется. Например, объявление функции strcat(), принятое в ANSI С, имеет такой вид:
char *strcat(char * restrict si, const char * restrict s2);
Вспомните, что функция strcat() добавляет копию второй строки в конец первой строки. Это приводит к модификации первой строки, но оставляет вторую строку неизмененной. Приведенное объявление отражает сказанное. Вскоре мы возвратимся к роли restrict.
Использование const с глобальными данными
Вспомните, что применение глобальных переменных считается рискованным подходом, поскольку данные открыты для ошибочного изменения любой частью программы. Такой риск исчезает, если данные являются константными, так что вполне разумно снабжать глобальные переменных квалификатором const. Можно иметь пе ременные const, массивы const и структуры const. (Структуры — это составной тип данных, который обсуждается в следующей главе.)
Однако необходимо соблюдать осторожность при совместном использовании константных данных в разных файлах. Для этого предусмотрены две стратегии. Первая заключается в следовании обычным правилам, применяемым в отношении внешних переменных — использование определяющих объявлений в одном файле и ссылочных объявлений (с ключевым словом extern) в других файлах:
Классы хранения, связывание и управление памятью 519
Читать дальшеИнтервал:
Закладка: