Все остальные операции над указателями запрещены.


Массивы и указатели

В языке C массивы и указатели тесно связаны друг с другом. Например, когда объявляется массив в виде int a[25], то при этом не только выделяется память для 25 элементов массива, но и формируется указатель с именем a, значение которого равно адресу первого по счету (нулевого) элемента массива. Доступ к элементам массива может осуществляться через указатель с именем a. С точки зрения синтаксиса языка указатель a является константой, значение которой можно использовать в выражениях, но изменить это значение нельзя.

Поскольку имя массива является указателем-константой, допустимо, например, такое присваивание:

int a[25];

int *ptr;

ptr=a;

В этом примере в переменную-указатель ptr записывается адрес начала массива a, т. е. адрес первого элемента массива.

Также справедливы следующие соотношения: например, имеется массив a[N], тогда истинными будут следующие сравнения:

a==&a[0];

*a==a[0].

Указатели можно увеличивать или уменьшать на целое число:

ptr=a+1;

Теперь указатель ptr будет указывать на второй элемент массива a, что эквивалентно &a[1].

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

int a[25];

int *ptr=a;

ptr+=3;

Первоначально указатель ptr указывал на начало массива a. После прибавления к переменной ptr числа 3 значение указателя увеличилось на 3*sizeof(int), а указатель ptr теперь будет указывать на четвертый элемент массива a. Указатель можно индексировать точно так же, как и массив. На самом деле компилятор преобразует индексацию в арифметику указателей, например, ptr[3]=10 представляется как *(ptr+3)=10.

К указателям типа void арифметические операции применять нельзя, так как им не ставится в соответствие размер области памяти.

Таким образом, в языке C для доступа к элементам массива существует два различных способа. Первый способ связан с использованием обычных индексных выражений в квадратных скобках, например, a[7]=3 или a[i+2]=5. При таком способе доступа записываются два выражения, причем второе выражение заключается в квадратные скобки. Первое из этих выражений должно быть указателем, а второе – выражением целого типа. Указатель, используемый в индексном выражении, не обязательно должен быть константой, указывающей на какой-либо массив, это может быть и переменная-указатель. В частности, после выполнения присваивания ptr=a доступ к седьмому элементу массива можно получить как с помощью константы-указателя a в форме a[7], таки переменной-указателя ptr в форме ptr[7].

Второй способ доступа к элементам массива связан с использованием адресных выражений и операции косвенной адресации в форме *(a+3)=10 или *(a+i+2)=5.

При реализации на компьютере первый способ приводится ко второму, т. е. индексное выражение приводится к адресному. Для приведенных примеров обращение к элементу массива a[3] преобразуется в *(a+3).

Для доступа к начальному элементу массива, т. е. к элементу с нулевым индексом, можно использовать просто значение указателя a или ptr, поэтому любое из присваиваний

*a=2;

a[0]=2;

*(a+0)=2;

*ptr=2;

ptr[0]=2;

*(ptr+0)=2;

присваивает начальному элементу массива значение 2.

Многомерные массивы в языке C – это массивы массивов, т. е. массивы, элементами которых, в свою очередь, являются массивы. При объявлении таких массивов в памяти компьютера создается несколько различных объектов. Например, при выполнении объявления двумерного массива int a2[4][3] в программе создается указатель a2, который определяет в памяти местоположение первого элемента массива и, кроме того, является указателем на массив из четырех указателей. Каждый из этих четырех указателей содержит адрес одномерного массива, представляющего собой строку двумерного массива и состоящего из трех элементов типа int, и позволяет обратиться к соответствующей строке массива.

Таким образом, объявление a2[4][3] порождает в программе три разных объекта: указатель с идентификатором a2, безымянный массив из четырех указателей и безымянный массив из двенадцати чисел типа int. Для доступа к безымянным массивам используются адресные выражения с указателем a2. Доступ к элементам массива указателей осуществляется с указанием одного индексного выражения в форме a2[2] или *(a2+2). Для доступа к элементам двумерного массива чисел типа int должны быть использованы два индексных выражения в форме a2[1][2] или эквивалентных ей *(*(a2+1)+2) и (*(a2+1))[2]. Следует учитывать, что с точки зрения синтаксиса языка C указатель a2 и указатели a2[0], a2[1], a2[2], a2[3] являются константами, и их значения нельзя изменять во время выполнения программы.

Размещение трехмерного массива происходит аналогично. Так, например, объявление float a3[3][4][5] порождает в программе, кроме самого трехмерного массива из 60 чисел типа float, массив из четырех указателей на тип float, массив из трех указателей на массив указателей на float и указатель на массив массивов указателей на float.

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

Например, обращение к элементу a2[1][2] можно осуществить при помощи указателяptr2, объявленного в форме int *ptr2=a2[0], как обращение ptr2[1×3+2] (здесь 1 и 2 – это индексы используемого элемента, а 3 – число элементов в строке) или какptr2[5]. Заметим, что внешне похожее обращение a2[6] выполнить невозможно, так как указателя с индексом 6 не существует.

Для обращения к элементу a3[2][3][4] из трехмерного массива тоже можно использовать указатель, описанный как float *ptr3=a3[0][0], с одним индексным выражением в форме ptr3[2×20+3×5+4] или ptr3[59].

Наши рекомендации