Указатели и массивы

В Си существует самая тесная связь между указателями и массивами, поэтому лучше эти средства рассматривать вместе.

Как мы знаем, структура массива полностью соответствует структуре оперативной памяти – элементы массива занимают в ней подряд идущие ячейки. Значит, если описан массив:

int mass[5];

то в оперативной памяти для его элементов выделяется пять подряд идущих ячеек:

К i-му элементу этого массива можно обратиться, назвав его индекс: mass[i] .

Доступ к любому элементу массива, осуществляемый по его индексу (номеру), может быть выполнен при помощи указателя, причем это будет сделано быстрее. Опишем переменную ptr как указатель на данные целого типа:

int *ptr;

В результате присваивания

ptr = &mass[0];

эта переменная будет содержать адрес начального (нулевого) элемента этого массива, то есть указатель ptr будет указывать на элемент mass[0]:

 

Адрес начального элемента любого массива называется базовым адресом этого массива. Таким образом, сейчас указатель ptr содержит базовый адрес массива mass . Если увеличить значение указателя на единицу, то ptr + 1 будет указывать на следующий элемент массива, то есть на mass[1] , ptr + 2 - на элемент mass[2] и так далее. В общем случае, если значение указателя увеличить на k , то можно получить адрес k-го элемента массива mass.

Значит, адрес любого элемента массива равен сумме его базового адреса, который является адресом его начального элемента, и смещения этого элемента от начала массива. Для начального (нулевого) элемента массива это смещение равно нулю, для первого элемента – единице, для второго – двум, для k-го оно равно k. Это верно для массива любого типа. Смысл выражения «увеличить указатель ptr на единицу » , как и смысл любой арифметики с указателями заключается в том, что ptr + 1 указывает на следующий за ptr элемент, а ptr + k на k-й после ptr элемент массива.

Между индексированием элементов массива и арифметикой с указателями существует очень тесная связь, потому что имя любого массива в Си есть адрес его начального элемента, то есть имя массива является его базовым адресом. Значит, в нашем примере присваивание:

ptr = &mass[0];

можно записать в другом виде:

ptr = mass;

Это будет одно и то же: записи &mass[0] и mass эквивалентны.

Из всего этого следует, что в общем случае запись &mass[k] будет эквивалентна записи (mass + k) , а сам k-й элемент массива можно определить как mass[k] или как *(mass + k). С другой стороны, если ptr – указатель, то в выражениях его можно использовать с индексом, то есть запись ptr[k] эквивалентна записи *(ptr + k).

Таким образом, элемент массива в Си разрешается изображать и в виде указателя со смещением, и в виде имени массива с индексом.

Между именем массива и указателем, выступающим в роли имени массива, однако существует различие. Указатель – это переменная, поэтому можно записать ptr = mass или ptr++. Но имя массива не является переменной, и записи типа mass = ptr или mass++ не допускаются.

Помимо рассмотренной операции сложения, над указателями можно выполнять следующие операции:

- складывать и вычитать указатели и целые данные,

- вычитать и сравнивать два указателя, ссылающиеся на элементы одного и того же массива,

- присваивать значение указателя другому указателю того же типа,

- присваивать указателю нуль и сравнивать его с нулем.

Над указателями нельзя выполнять следующие операции:

- складывать два указателя, перемножать их, делить, сдвигать, выделять разряды,

- складывать указатели со значениями типа float и double,

- присваивать указателю одного типа значение указателя другого типа (исключение составляют указатели типа void).

Указатели можно использовать и при работе с многомерными массивами:

int trio[5][2][3];

int *i_ptr;

Описан трехмерный массив trio целого типа и указатель ptr на данные целого типа. Присвоим этому указателю значение базового адреса массива:

i_ptr=&trio[0][0][0];

Необходимо учесть, что для многомерных массивов нельзя использовать операцию присваивания базового адреса указателю в таком виде:

i_ptr=trio;

как это имеет место для векторов (одномерных массивов).

Доступ к j-му элементу i-ой строки k-го слоя массива trio может быть осуществлен или с помощью индексов:

trio[k][i][j]=1;

либо с помощью указателей:

*(i_ptr + k*(2*3) + i*3 + j)=1;

Как и в Паскале, в языке Си запрещается присваивать значения элементов одного массива другому массиву целиком:

float r[2][2], s[2][2];

r = s; // ошибка!

Эти ограничения можно обойти с помощью указателя:

float *f_ptr;

f_ptr = &s[0][0];

r = *f_ptr;

При этом элементам массива r будут присвоены значения соответствующих элементов массива s.








Дата добавления: 2015-10-19; просмотров: 1504;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.007 сек.