Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб по С и C++.doc
Скачиваний:
216
Добавлен:
25.03.2015
Размер:
1.34 Mб
Скачать

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

Связь указателей и массивов с одним измерением справедливо и для массивов с большим числом измерений. Например, рассмотрим двумерный массив

floatm[5][10];

Если рассматривать его как массив пяти массивов размерностью по десять элементов каждый, то очевидна схема его размещения в памяти - последовательное размещение «строк» элементов. Обращению к элементам m[i][j] соответствует эквива­лентное выражение *(*(m+i)+j), а объявление этого массива указателем будет:

float**m;

Таким образом, имя двумерного массива - имя указателя на указатель.

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

m

значения

Ука-

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]

рис. 1

Cхема размещения такого массива в памяти - последова­тельное (друг за другом) размещение строк - одномерных массивов со значениями.

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

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]

Таким образом, указатели на указатели – это имена многомерных массивов.

Очевидна эквивалентность выражений:

&name[0][0] <-> &(**name) <->name// адрес нулевого элемента матрицы

**name<->name[0][0] // значение нулевого элемента матрицы

Пример программы:

#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 в виде

z[3][4]={ 1, 2, 3, 4, 11,12,13,14, 21,22,23,24}; // Декларация и инициализация матрицы целых чисел

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