Указатели на указатели


В языке Си можно описать переменную типа «указатель на указатель». Это ячейка оперативной памяти, в которой будет храниться адрес указателя на какую либо переменную. Признак такого типа данных – повторение символа «*» перед идентификатором переменной. Количество символов «*» определяет уровень вложенности указателей друг в друга. При объявлении указателей на указатели возможна их одновременная инициализация. Например:

int a=5;

int *p1=&a;

int **pp1=&p1;

int ***ppp1=&pp1;

Теперь присвоим целочисленной переменной а новое значение, например 10. Одинаковое присваивание произведут следующие операции:

a=10; *p1=10; **pp1=10; ***ppp1=10;

Для доступа к области ОП, отведенной под переменную а можно использовать и индексы. Справедливы следующие аналоги, если мы работаем с многомерными массивами:

*p1 <-> p1[0] **pp1 <-> pp1[0][0] ***ppp1 <-> ppp1[0][0][0]

Отметим, что идентификатор двухмерного массива – это указатель на массив указателей (переменная типа указатель на указатель: int **m;), поэтому выражение а[i][j] эквивалентно выражению *(*(m+i)+j).

Например, двуxмерный массив m[3][4]; компилятор рассматривает как массив четырех указателей, каждый из которых указывает на начало массива со значениями размером по три элемента каждый.

 

Ука­за­тели m[0] ® m[0][0] m[0][1] m[0][2] m[0][3] *(*(m+i)+j)
m[1] m[1][0] m[1][1] m[1][2] m[1][3]
m[2] m[2][0] m[2][1] m[2][2] m[2][3]

(А) (В)

Рис. 4

 

Очевидна и схема размещения такого массива в памяти - последовательное (друг за другом) размещение "строк" - одномерных массивов со значениями. Аналогичным образом можно установить соответствие между указателями и массивами с произвольным числом измерений:

float name[][][][]; « float ****name;

 

Пример программы конструирования массива массивов:

#include <stdio.h>

int x0[4]={ 1, 2, 3, 4};

int x1[4]={11,12,13, 14}; // Декларация и инициализация

int x2[4]={21,22,23, 24}; // массивов целых чисел

int *y[3]={x0,x1,x2}; // Создание массива указателей

void main(void)

{ int i,j;

for (i=0; i<3; i++)

{ printf("\n %2d)",i);

for (j=0; j<4; j++) printf(" %2d",y[i][j]);

}

}

 

Результаты работы программы:

0) 1 2 3 4

1) 11 12 13 14

2) 21 22 23 24

 

Такие же результаты будут получены и при таком объявлении массива:

int y[3][4]={

{ 1, 2, 3, 4},

{11,12,13,14}, // Декларация и инициализация

{21,22,23,24}, // массива массивов целых чисел

};

В последнем случае массив указателей на массивы создается компилятором. Здесь собственно данные массива располагаются в памяти последовательно по строкам, что является основанием для объявления массива y в следующем виде:

int z[3][4]={ 1, 2, 3, 4,

11,12,13,14, // Декларация и инициализация

21,22,23,24}; // массива массивов целых чисел

Замена скобочного выражения z[3][4] на z[12] здесь не допускается, так как массив указателей в данном случае создан не будет.

 

Адресная функция

Использование многомерных массивов в языке Си связано с расходами оперативной памяти на массивы указателей.

Можно избежать таких расходов, если ввести адресную функцию для доступа к элементам одномерного массива (цепочка одномерных массивов со значениями) по значениям индексов многомерного массива. Например, адресная функция для следующего трехмерного массива x(1..n1, 1..n2, 1..n3) выглядит следующим образом:

L(i, j, k)=n1*n2*(i-1) + n2*(j-1)+k,

где индексы принадлежат диапазонам: i=1..n1, j=1..n2, k=1..n3.

Для размещения такого массива требуется область оперативной памяти размером n1*n2*n3*(число байт отводимых компилятором для одного элемента массива в зависимости от типа данных). Рассматривая такую область как одномерный массив y размером n1*n2*n3 можно установить соответствие элемента массива х элементу памяти для его размещения:

x(i, j, k)=y(L(i, j, k));

 

Так как массивы являются данными сложного (составного) типа, операции над ними желательно выполнять, используя стандартные библиотечные функции, например, для объявленных массивов: type x[100], y[100]; операция присваивания:

memcpy(x,y,sizeof(x)); - содержимое массива y присвоить содержимому массива x.

 



Дата добавления: 2016-09-26; просмотров: 1234;


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

Воспользовавшись поиском можно найти нужную информацию на сайте.

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

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.008 сек.