Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование / WORD / Лекции по ЯП (часть 3).doc
Скачиваний:
138
Добавлен:
15.04.2015
Размер:
1.34 Mб
Скачать

Указатели и многомерные массивы

Имя массива без квадратных скобок представляет собой указатель на первый элемент массива. Благодаря этому обращение к некоторым типам массивов легче выполнять через указатели, чем через индексы массива. Но все рассмотренные ранее примеры относились только к одномерным массивам. А как насчет многомерных?

Пусть имеем следующее определение:

int arr[2][4];

Вот как следует интерпретировать составные части этого объявления.

1. Объявление массива arr.

2. В массиве arr — два элемента.

3. Каждый из этих двух элементов содержит четыре элемента.

4. Каждый из этих четырех элементов имеет тип int.

Объявление многомерного массива следует читать слева направо, начиная с его имени, по одной паре скобок за раз. Как только прочитана последняя пара скобок (последнее измерение массива), переходите в начало объявления, чтобы узнать тип элементов массива.

Попробуем ответить на следующие вопросы:

Что представляет собой имя массива arr?

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

А что в этом контексте представляет собой первый элемент arr?

Это вовсе не элемент arr[0][0] типа int, как можно было бы подумать. Вспомните, что multi — это массив массивов, так что его первым элементом будет arr[0], который в свою очередь представляет собой массив из четырех значений типа int (всего multi содержит два таких массива).

Раз arr[0] представляет из себя массив, является ли его имя указателем? Конечно! Имя arr[0] указывает на первый элемент массива, т.е. multi[0][0].

Согласно схеме «массив массивов», многомерный массив можно представить себе так, как показано на рисунке:

Т.о. в нашем примере arr и arr[0] являются указателями, a arr[0][0] — элементом массива.

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

printf("arr = %u", arr);

printf("arr [0] = %u", arr [0]);

printf("&arr [0][0] = %u", &arr [0][0])

Адрес массива arr равен адресу массива arr[0], и оба эти адреса вместе равны адресу первого целочисленного : массива arr[0][0].

sizeof (arr) = 32;

sizeof (arr[0]) = 16;

sizeof (arr [0][0]) = 4;

В различных системах эти размеры могут отличаться. Если у вас 32-разрядная операционная система, то скорее всего числа будут именно такими: 32, 16 и 4, потому что в подобных системах значение типа int занимает четыре байта. В более старых 16-разрядных системах результат может состоять из чисел 16, 8 и 2.

В нашем примере имеем следующее. Указатель arr указывает на массив из четырех целочисленных элементов общей длиной 16 байт. При инкрементировании arr он увеличивается на 16, т.е. на размер указываемого элемента. Если arr указывает на элемент arr[0], то (arr+l) указывает на arr[1].

Мы убедились, что arr — это указатель на arr[0]. В свою очередь, arr[0] также является указателем, но уже на arr[0][0]. Поэтому arr представляет собой указатель на указатель. Для того чтобы обратиться через arr к элементам массива, следует пользоваться двойной ссылкой по указателю. Например, чтобы посмотреть значение arr[0][0], можно воспользоваться любым из следующих трех операторов:

arr [0][0]

* arr [0]

** arr;

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

Работая с многомерными массивами, имейте в виду следующее: массив n-й размерности состоит из элементов, являющихся массивами n-1-й размерности. Когда n доходит до 1, элементы соответствующего массива становятся переменными того типа, с которым объявлен массив.

Как пользоваться указателями в многомерном массиве?

int arr [2][4];

.

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

int (*ptr)[4];

Теперь сделаем так, чтобы ptr указывал на первый элемент arr:

ptr = arr;

Квадратные скобки [ ] имеют более высокий приоритет, чем операция ссылки *.

Поэтому если убрать скобки:

int *ptr[4];

этот оператор объявляет массив из четырех указателей на значения типа int, а не указатель на массив.

Далее как и в случае одномерных массивов, указатели используются для передачи массивов в функции. Это иллюстрируется следующим примером, в котором многомерный массив передается в функцию двумя способами.

void printarray_l(int (*ptr)[4]);

void printarray_2 ( int (*ptr)[4], int n);

main() {

int multi[3][4] = { { 1, 2, 3, 4 },

{ 5, 6, 7, 8 },

{ 9, 10, 11, 12 } };

/* ptr - указатель на массив из четырех чисел типа int. */

int (*ptr)[4], count;

/* Установить ptr на первый элемент массива multi. */

ptr * multi;

/* При каждом проходе цикла ptr указывает на очередной элемент */

/* (т.е. oчередной 4 -элементный .целый массив) массива multi. */

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

printarray_l(ptr++);

puts("\n Нажмите Enter...");

getchar();

printarray_2(multi, 3);

}

void printarray_l (int (*ptr) [ 4 ])

{

/* Вывод элементов массива из четырех целых чисел. */

/* р указывает на переменную типа int. Необходимо приведение */

/* типа для присвоения указателю р адреса из ptr. */

int *p, count;

р = (int *)ptr;

for (count = 0; count < 4; count++)

printf("\n%d", *p++);

}

void printarray_2(int (*ptr)[4], int n) {

/* Вывод элементов n массивов по четыре числа в каждом. */

int *p, count; р = (int *)ptr;

for (count = 0; count < (4 * n); count++)

printf("\n%d",*p++);}

В функцию printarray_l () передается всего один аргумент — указатель на массив из четырех целочисленных значений. Эта функция выводит на экран все четыре элемента переданного массива. При первом вызове функции printarray_l () из main() в нее передается указатель на первый элемент массива multi (его первый четырехэлементный массив). Затем функция вызывается еще два раза, причем указатель инкрементируется так, чтобы указывать соответственно на второй и третий элементы multi. После трех вызовов функции все 12 элементов массива multi оказываются выведенными на экран.

Во второй функции, printarray_2 (), применяется другой подход. В нее также передается указатель на массив четырех целочисленных значений. Но, кроме того, в нее передается целый аргумент, задающий количество элементов многомерного массива, на который фактически и указывает первый аргумент. Все содержимое массива multi выводится на экран одним-единственным вызовом функции printarray_2 ().

В обеих функциях для перебора целочисленных элементов массива используется обращение по указателю. Выражение (int *) представляет собой явное преобразование типа, которое временно изменяет объявленный тип переменной на другой во время присваивания ее значения. Преобразование типа необходимо при присвоении значения ptr указателю р, поскольку они являются указателями на разные типы данных (р указывает на int, a ptr — на массив из четырех чисел типа int). В языке С указателю одного типа нельзя присваивать значение указателя другого типа. Приведение типа приказывает компилятору следующее: "В этом операторе считать ptr указателем на int".