Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Visual_C_console.pdf
Скачиваний:
34
Добавлен:
16.05.2015
Размер:
954.14 Кб
Скачать

84

Арифметические и логические операции с указателями

Любой объект программы имеет строго определенную длину, определяемую типом объекта. Если указатель связан с объектом, то компилятору эта длина известна. Поэтому, когда указатель связан с массивом, увеличение значения указателя на 1 настраивает указатель на следующий элемент этого массива (а не на следующий байт памяти, если элемент имеет длину более одного байта). Таким образом, выполняя арифметические операции с указателем можно его настраивать на другие элементы массива, аналогично тому, как это выполняется с помощью индексов.

На операции, которые можно выполнять с указателями, налагаются ограничения.

1.Скалярные указатели можно приравнивать друг другу, если они связаны с элементами данных одного и того же типа. Пусть

int *p, *q;

double *s, *t;

тогда допускается операция p = q; (или q = p;),

но не допускается операция p = s; (или p = t;).

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

Указатели-константы не могут записываться с левой стороны от знака равенства, поскольку они являются константами, и после такого присваивания массив, с которым связан указатель, будет утерян в памяти программы. Потребность в этом возникает при необходимости совмещения двух или более массивов или разнотипных данных. В этом случае можно воспользоваться преобразованием типа reinterpret_cast (см. параграф «Преобразование типов»).

85

3.Указатели на данные типа void можно преобразовывать для обращения к элементам данных любых типов. Например, указатель на тип данных void преобразуется в указатель на тип данных double (эта операция называется явным приведением типа), с помощью указанной ниже формы записи

void *p; double *q;

...

q = (double*)p;

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

int *ptr, j, x[20];

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

ptr = x;

то выражение ptr++ после вычисления однозначно будет указывать на элемент x[1]. Аналогично, после выполнения действий

ptr = x; j = 3;

ptr = ptr + 2 * j + 1;

указатель ptr будет указывать на элемент x[7]. Если при вычислении выражения с указателем получится значение адреса за пределом массива, то действия программы непредсказуемы. Нарушение границ массивов в языке C++ не проверяется.

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

6.Указатели, связанные с одним и тем же массивом (один из этих указателей может быть только скалярным), можно сравнивать на

86

"больше" или "меньше", а также на "равенство" или "неравенство". Указатели можно также сравнивать со специальным символом NULL, который обозначает пустой указатель (не связанный с конкретным адресом). Такое значение обычно указатель получает, если при запросе память не была выделена.

7.Никакие операции с указателями, кроме перечисленных, не допускаются, т.е. не разрешены умножение (и деление) указателя на указатель или умножение указателя на число, а также суммирование с числами типа double, поскольку при этом получаются адреса памяти, не имеющие отношения к программе.

Обработка массивов с помощью указателей

Спомощью указателей можно обрабатывать массивы. При этом возможны два варианта:

Использование альтернативной формы записи индексов массива (например, запись *(a + i) вместо a[i]). Кроме потери наглядности этот способ никаких преимуществ не имеет, поэтому его следует назвать “использование псевдо указателей”;

Использовать рабочие указатели.

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

//Вычисление средних арифметических значений по строкам матрицы.

#include "stdafx.h" #include <conio.h> #include <iostream> using namespace std; #define ROW 2 #define COL 3

87

double average(double x[ ], int m); // Прототип функции void _tmain()

{

double a[ROW][COL], *pt, *qt;

int i = 0; // Эта переменная для подсказки ввода № строки /* Если в объявленной матрице указан только один индекс, то это указатель на строку матрицы, например, qt = a[0]; */

for (qt = a[0]; qt < a[0] + ROW * COL; qt += COL )

{

cout << "Введите строку матрицы " << (i + 1) << endl;

for (pt = qt; pt < qt + COL; pt++) cin >> *pt;

i++; // Подсчет номера строки

}

cout << "\nСредние арифметические по строкам" << endl;

for (qt = a[0]; qt < a[0] + ROW * COL; qt += COL ) cout << average (qt, COL) << endl;

_getch();

}

//Функция вычисления среднего арифметического для вектора

//x[ ] – одномерный массив, m - длина массива

double average(double x[ ], int m)

{

double *pt, sum = 0; for(pt = x; pt <x + m; pt++)

sum += *pt; return sum / m;

}

В примере рабочий указатель qt настраивается на начало каждой строки матрицы (когда после имени объявленной матрицы указывается только один индекс, то это указатель на строку матрицы с этим

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]