Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Семестр_2_С++.doc
Скачиваний:
4
Добавлен:
23.04.2019
Размер:
217.09 Кб
Скачать

7.3. Арифметические операции и операции сравнения

Основными арифметическими операциями, применимыми к указателям, являются операции увеличения и уменьшения указателя:

ИмяУказателя + i ИмяУказателя - i

здесь ИмяУказателя – переменная типа указатель;

i - значение целочисленного типа.

Результатом операции (ИмяУказателя + i) является указатель на i – ый элемент после элемента, адрес которого находится в данном указателе, а (ИмяУказателя - i) – указатель на i – ый элемент до элемента, адрес которого находится в данном указателе.

Допустимыми при работе с указателями являются операции инкремента (++) и декремента (--). Выполнение этих операций аналогично соответствующим операциям над целочисленными типами, т. е. указатель будет смещаться (увеличиваться или уменьшаться в зависимости от операции) на один элемент. Фактически указатель (адрес) изменится на количество байт, занимаемых этим элементом в памяти.

Как известно, переменные в зависимости от типа занимают разное количество ячеек в памяти компьютера. Поэтому использование операции инкремента (++) к переменной-указателю на тип short int изменит адрес на 2, т. е. сдвинется на два байта, а для переменной-указателя на тип float- на четыре.

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

ИмяУказателя1 -ИмяУказателя2

Операция имеет смысл, только если обе переменные являются указателями на один и тот же набор данных (например, массив). Результатом операции является целое число, равное количеству элементов, которые можно расположить между ячейками памяти, на которые указывают указатели ИмяУказателя1, ИмяУказателя2.

Для указателей определяются операции отношения:

== , >, = >, < , <=, !=

При этом сравниваются адреса, записанные в переменные-указатели. Результатом операций сравнения является целое число (0 или 1).

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

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

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

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

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

ИмяМассива [Индекс]

является выражением с двумя операндами. Первый из них ИмяМассива – константный указатель на начало массива в памяти, второй Индекс - выражение целого типа, определяющее смещение от начала массива на Индекс*sizeof(ИмяТипа) байт, где ИмяТипа - имя базового типа массива.

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

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

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

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

БазовыйТип* ИмяУказателя = ИмяМассива;

В этом случае доступ к элементам массива можно осуществлять как с помощью индексирования имени массива, так и с помощью введенного указателя на начало массива. Например, доступ к i-ому элементу вещественного одномерного массива, объявленного

float A[10]; ,

адрес начала которого хранится в указателе p,

float* p = A;

возможен несколькю способами:

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

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

Например, обнуление целочисленного массива A с помощью указателя p будет иметь вид:

int A[10];

int* p = A;

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

{

*(p + i) = 0; // аналогично A[i] = 0;

}

или

for(int* p = A; p < A + 10; p++)

{

*p = 0;

}

А ввод элементов массива с помощью указателя можно записать следующим образом:

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

{

cout << "Введите A[" << i << "] = ";

cin >> *(p+i);

}