Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР15-С++24-мая-2012.doc
Скачиваний:
23
Добавлен:
23.09.2019
Размер:
1.07 Mб
Скачать

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

Указатели как и переменные любого другого типа, могут объединяться в массивы. Объявление массива указателей из 10 элементов имеет вид int *x[10];. Каждому из элементов массива можно присвоить адрес. Например, пятому элементу этого массива присвоим адрес целой и ранее объявленной переменной у: х[4]=&у;. Если затем необходимо найти значение переменной у, это можно сделать, используя конструкцию *х[4].

C помощью массива указателей несложно запрограммировать динамическое создание двумерных массивов. Объявим массив 10 указателей p:

int *p[10];

C каждым из них можно связать динамически созданный одномерный массив и интерпретировать его как строку матрицы:

for (i=0; i<=8; i++) //Цикл по строкам

{p[i]=new int[20];} // Создание строки.

В результате получили следующую замысловатую конструкцию. Идентификатор p является именем массива указателей, которые содержат адреса первых элементов других массивов — строк матрицы. Выражение p[k] или равносильное ему *(p+k) представляют собой адрес первого элемента строки с номером k. Выражение *(p[k]+m) или *(*(p+k)+m) — элемент с номером m строки с номером k, то есть элемент двумерного массива, расположенный в строке k и столбце m. Заметим также, что динамически созданные «строки матрицы» не обязательно должны иметь одинаковый размер, а само понятие «матрица» в данном контексте уместно заменить выражением «массив массивов».

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

Если рассматривать предыдущий массив (int a[2][3];) как массив двух массивов размерностью по три элемента каждый, то обращение к элементу а[i][j] соответствует эквива­лентное выражение *(*(а+i)+j), а объявление этого массива с использованием указателей будет иметь вид

int **а;

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

Указатели могут ссылаться на другие указатели. При этом в ячейках памяти, на которые будут ссылаться первые указатели, будут содержаться не значения, а адреса вторых указателей. Число символов * при объявлении указателя показывает порядок указателя. Чтобы получить доступ к значению, на которое ссылается указатель его необходимо разыменовывать соответствующее количество раз. Разработаем программу, которая будет выполнять некоторые операции с указателями порядка выше первого.

// pointer.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"

#include <iostream>

using namespace std;

  

int _tmain(int argc, _TCHAR* argv[])

{

    int var = 123; // инициализация переменной var числом 123

    int *ptrvar = &var; // указатель на переменную var

    int **ptr_ptrvar = &ptrvar; // указатель на переменную var

    int ***ptr_ptr_ptrvar = &ptr_ptrvar;

    cout << " var\t\t= " << var << endl;

    cout << " *ptrvar\t= " << *ptrvar << endl;

    cout << " **ptr_ptrvar   = " << **ptr_ptrvar << endl; // два раза разименовываем указатель, так как он второго порядка 

    cout << " ***ptr_ptrvar  = " << ***ptr_ptr_ptrvar << endl; // указатель третьего порядка

    cout << "\n ***ptr_ptr_ptrvar -> **ptr_ptrvar -> *ptrvar ->      var -> "<< var << endl;

    cout << "\t  " << &ptr_ptr_ptrvar<< " -> " << "    " << &ptr_ptrvar << " ->" << &ptrvar << " -> " << &var << " -> " << var << endl;

    system("pause");

    return 0;

}

На рис. 15. 3 показан результат работы программы.

Рис. 15. 3. Указатели в С++

Данная программа доказывает тот факт, что для получения значения количество разыменований указателя должно совпадать с его порядком. Логика n-кратного разыменования заключается в том, что программа последовательно перебирает адреса всех указателей вплоть до переменной, в которой содержится значение. В программе показана реализация указателя третьего порядка. И если, используя такой  указатель (третьего порядка) необходимо получить значение, на которое он ссылается, делается 4 шага:

1. По значению указателя третьего порядка получить адрес указателя второго порядка;

2. По значению указателя второго порядка получить адрес указателя первого порядка;

3. По значению указателя первого порядка получить адрес переменной;

4. По адресу переменной получить доступ к её значению.

Данные четыре действия показаны на рисунке 3 (две предпоследние строки). Верхняя строка показывает имена указателей, а нижняя строка их адреса.

На рис. 15. 4 показана схема разыменовывания указателя третьего порядка из верхней программы. Суть в том, что указатели связаны друг с другом через свои адреса. Причём, например, для указателя ptr_ptrvar данное число  0015FDB4 является  адресом, а для указателя ptr_ptr_ptrvar это же число является значением.

Рис. 15.4. Указатели в С++

Именно таким образом выполняется связка указателей. Вообще говоря, указатели порядка выше первого используются редко, но данный материал поможет понять механизм работы указателей.