ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4246
Скачиваний: 28
Глава 5. Указатели и массивы
71
Но:
const int n = 2;
int *p = NULL; /* p – указатель на переменную */
p = &n; /* ошибка, так как p – указатель на переменную */
Указатель на константу запрещает косвенное изменение этой
константы. Например:
const int n = 2;
const int *p = &n; /* p – указатель на константу */
(*p)++; /* ошибка, так как p – указатель на константу */
Отметим, что указателю на константу может быть присвоен адрес
переменной. Например:
int n = 2;
const int *p = &n; /* p – указатель на константу */
p = &n; /* правильно */
Значение константного указателя изменять нельзя. Например:
int n = 2;
int* const p = &n; /* p – константный указатель */
(*p)++; /* правильно, n = 3 */
p++; /* ошибка, так как p – константа */
Теперь объявим константный указатель на константу. В этом
случае нельзя изменить как значение такого указателя, так и зна-
чение константы, на которую он ссылается. Например:
const int n = 2;
const int* const p =&n; /* конст. указатель на константу */
(*p)++; /* ошибка, так как n – константа */
p++; /* ошибка, так как p – константа */
5.5. Одномерные массивы
Массив
— это последовательность данных одного типа, которые
хранятся в непрерывной области памяти друг за другом. Единица
данных массива называется
элементом
массива. Доступ к эле-
ментам массива производится по их номерам в последовательно-
Часть I. Язык программирования С
72
сти, которые называются
индексами
. Одномерный массив объяв-
ляется следующим образом:
спецификатор_типа идентификатор[диапазон];
Здесь
спецификатор_типа
определяет тип элементов массива,
иден-
тификатор
задает имя массива, а
диапазон
— количество элемен-
тов в массиве. При этом имя массива является константным ука-
зателем на его первый элемент, а
диапазон
должен быть задан по-
ложительным целочисленным литералом или именованной
константой. Например:
int a[10]; /* массив из десяти целых чисел */
При объявлении массива его можно явно инициализировать, пе-
речислив значения элементов массива в фигурных скобках в по-
рядке возрастания индекса. Например:
char s[3] = {'a', 'b', 'c'};
int a[3] = {0, 1, 2};
При инициализации массива возможны три ситуации:
размер массива равен количеству значений в списке инициа-
лизации;
размер массива больше количества значений в списке инициа-
лизации;
размер массива меньше количества значений в списке инициа-
лизации.
В первом случае происходит обычная инициализация элементов
массива. Во втором случае оставшиеся неинициализированными
элементы массива инициализируются нулями. В третьем случае
компилятор выдаст сообщение об ошибке.
Если значения элементов массива перечисляются явно, то раз-
мерность массива можно не указывать. В этом случае компилятор
сам определит размерность по количеству элементов. Например:
int a[] = {0, 1, 2}; /* массив из трех элементов */
Доступ к элементам массива выполняется при помощи
операто-
ра индексирования
, который имеет следующий вид:
имя_массива[индекс]
Глава 5. Указатели и массивы
73
Возвращает оператор индексирования L-value. При этом выход
индекса за пределы допустимого диапазона не проверяется. На-
пример:
int a[3] = {0, 1, 2};
int n;
n = a[0];
a[0] = 10;
Особенно отметим, что нумерация элементов массива начинается
с нуля. Приоритет оператора индексирования превышает приори-
тет унарных арифметических и побитовых операторов и совпада-
ет с приоритетом постфиксных операций инкремента и декре-
мента.
Так как верхний предел индекса массива может использоваться в
программе многократно, то его лучше определить как именован-
ную константу. В этом случае легче вносить изменения в про-
грамму при изменении размерности массива. Например:
const int n = 10;
int a[n]; /* массив из десяти целых чисел */
В связи с этим возникает вопрос, какой модификатор знака вы-
брать для типа индекса массива
unsigned
или
signed
. Так как ин-
дексы это неотрицательные целые числа, то можно предполо-
жить, что лучше использовать модификатор знака
unsigned
. Но на
практике для индекса обычно выбирают модификатор знака
signed
, т. к. в этом случае легче находить ошибки, связанные с
неправильным изменением значения индекса.
Так как имя массива фактически представляет собой указатель,
то оператор индексирования может применяться к любым указа-
телям. Отсюда следует, что имя массива может также быть опе-
рандом оператора разыменования.
В языке программирования С++ имя массива имеет следующий
тип:
спецификатор_типа[диапазон]
Однако этот тип неявно приводится к типу указателя на
специфи-
катор_типа
.
Часть I. Язык программирования С
74
5.6. Строки
Строкой
называется массив символов, который заканчивается
пустым символом
\0
. Для инициализации строки используются
строковые литералы. Если длина массива больше чем длина
строкового литерала, то оставшиеся свободными байты инициа-
лизируются нулями. Например:
char s[10] = "string";
Если длина строки должна быть равна длине строкового литера-
ла, то размерность массива лучше не указывать, ее подсчитает
сам компилятор. Например:
char s[] = "string";
Пустую строку можно объявить следующим образом:
char s[10] = "";
В языке программирования C для работы со строками существует
большое количество функций, прототипы которых описаны в за-
головочном файле и string.h. Работа с этими функциями будет
рассмотрена в
гл. 29
.
5.7. Арифметические действия
с указателями
Над указателями одного типа можно выполнять арифметическую
операцию вычитания
-
. Результатом этой операции будет целое
число, которое указывает, на сколько один адрес памяти смещен
относительно другого в единицах, равных длине базового типа
данных указателей. Например:
int a[5];
int n, m;
n = &a[5] - &a[3]; /* n = 2 */
m = &a[3] - &a[5]; /* m = -2 */
К указателю можно прибавить или вычесть целое число. В этом
случае значение указателя соответственно увеличится или
Глава 5. Указатели и массивы
75
уменьшится на это число, умноженное на длину базового типа
данных указателя. Например:
int a[5];
int *p = a+2; /* p = &a[2] */
К указателю можно применять операции
++
и
--
. В этом случае
значение указателя соответственно увеличится или уменьшится
на длину базового типа данных указателя. Например:
double* p;
++p;
5.8. Многомерные массивы
Массив, элементы которого нумеруются несколькими индексами,
называется
многомерным
. Компилятор должен поддерживать
многомерные массивы, элементы которых нумеруются, по край-
ней мере, 12 индексами. Объявляется многомерный массив сле-
дующим образом:
спецификатор_типа идентификатор[диапазон_1]...[диапазон_n];
Тип многомерного массива определяется следующим образом:
спецификатор_типа(*)[диапазон_2]...[диапазон_n]
Причина такой типизации заключается в том, что при объявлении
многомерного массива память резервируется под все элементы
массива сразу, а сами элементы массива располагаются по стро-
кам. Такое решение было принято для увеличения производи-
тельности программы при работе с многомерными массивами.
Например, двумерный целочисленный массив может быть объяв-
лен как:
int arr[2][2];
В этом случае
arr
является именованной константой, тип которой
равен
int(*)[2]
.
При инициализации многомерного массива его элементы заклю-
чаются в фигурные скобки. Например:
int a[2][2] = {1, 1, 2, 2};