Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ГЛАВА 8 Указатели и массивы.doc
Скачиваний:
57
Добавлен:
29.02.2016
Размер:
142.85 Кб
Скачать

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

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

  • доступ к элементам массива

  • передача одномерных массивов в функцию

Указатели и двумерные массивы

  • массивы указателей

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

  • массивы указателей и двумерные массивы

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

Одно из основных применений указателей – работа с массивами. В языке С++ указатели и массивы тесно связаны между собой. В С++ указатель, который ссылается на массив, можно индексировать так, как если бы это было имя массива.

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

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

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

Имя массива является константным указателем на начало массива.

Применение операции адреса (&) к первому элементу массива даст адрес массива. Например, если объявлен массив

int mas[6];

то записи mas и &mas[0] эквивалентны и определяют адрес 1-го элемента массива, т.е. адрес самого массива. Оба значения являются константами типа указатель, их нельзя изменять на протяжении всей работы программы. Однако эти значения можно присваивать переменным типа указатель:

int mas[6];

int * p;

p = &mas[0]; // или p = mas; – указателю p

// присваивается адрес массива

Индекс элемента массива означает смещение элемента от начала массива на величину, равную

индекс * sizeof(тип)

байтов, где тип – тип элементов массива.

Используя операцию разыменования (*), действие операции индексирования ([]) можно объяснить так:

имя_массива[индекс] = *(имя_массива + индекс)

Поэтому, например, для массива mas записи

mas[i] и *(mas + i) обозначают одну величину – значение соответствующего элемента массива, а записи

&mas[i] и (mas + i) обозначают один адрес элемента.

Индекс элемента массива определяет не его номер, а смещение относительно начала массива. Именно этим объясняется то, что индексы массивов начинаются с нуля.

Доступ к элементам массива

Если указателю присвоен адрес массива, то доступ к элементам массива можно осуществлять как с помощью индексирования имени массива, так и с помощью введенного указателя на начало массива. Если указатель p указывает на некоторый элемент массива, то p + 1 указывает на следующий элемент, p + i – на i-ый элемент после p, а p – i – на i-ый элемент перед p. Другими словами, если p указывает на mas[0], то:

(p+i) – адрес элемента mas[i]

*(p+i) – содержимое элемента mas[i]

Отсюда следует, что доступ к i-ому элементу одномерного массива mas, адрес начала которого хранится в указателе p, возможен следующими способами:

mas[i] *(mas + i) p[i] *(p + i)

При работе с массивами возможен любой из предлагаемых вариантов. Однако следует отметить, что компилятор преобразует все индексные выражения в адресные, т.е. встречая запись mas[i], компилятор преобразует её в *(mas+i), а запись p[i] – в *(p + i).

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

Несмотря на то, что объявления

int mas[6]; и int * p;

во многом схожи, они не являются полными аналогами.

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

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

int *p; p = mas;

int y = *p; // содержимое mas[0] присваивается y

*p++; p++;

(*p)++;

Выражение *p++ разыменовывает указатель *p и передвигает его к следующему элементу массива. Это возможно, поскольку известен тип адресуемых данных, а значит, и их размер. Выражение (*p)++ – разыменовывает указатель *p и к значению добавляет единицу.

А имя массива – это указатель-константа, поэтому следующие операторы не допускаются:

mas = p; mas++; *mas++;

Язык С++ позволяет программам разыменовывать имена массивов с помощью такого выражения, как *имя_массива:

int mas[5];

int x = *mas; // x = mas[0]

*mas = 77; // mas[0] = 77;

cout<<&mas<<" "<<&mas[0]; // вывод адреса массива mas

// Пример 8.1 Адресация элементов одномерного массива mas.

#include <iostream>

using namespace std;

const int n = 5;

int main(){

int mas[n]; // массив из n целых чисел

int * p = mas; // p – указатель на массив типа int

for(int i = 0; i < n; i++) // инициализация элементов массива,

mas[i] = i; // используя индекс

for(int i = 0; i < n; i++) // вывод массива, используя

cout<<*p++<<' '; // указатель p0 1 2 3 4

cout<<endl;

for(int i = 0; i < n; i++){

p = &mas[i];

cout<<*p<<' '; // 0 1 2 3 4

}

cout<<endl;

for(int i = 0; i < n; i++)

cout<<*(mas+i)<<' '; // 0 1 2 3 4

cout<<endl;

p = mas; *p = 5;

for(int i = 0; i < n; i++)

cout<<(*p)++<<' '; // 5 6 7 8 9

cout<<endl;

for(int * p = mas; p < mas + n; p++) // обнуление элементов

*p = 0; // массива mas – 0 0 0 0 0

system("pause");

}

Следует отметить, что нельзя выполнить оператор

int *q = &mas; // нельзя, т.к. типы не совпадают

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

int *q = (int*)&mas; // можно, выполнили приведение типа

cout<<q<<endl; // можно, вывод адреса массива mas