Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка для изучения основ С++ 7 указатели.doc
Скачиваний:
69
Добавлен:
20.05.2015
Размер:
156.67 Кб
Скачать

Упражнение

Есть ли ошибки в данных определениях? Поясните. Как бы вы их исправили?

(a) int ival = 1.01; (b) int &rval1 = 1.01;

(c) int &rval2 = ival; (d) int &rval3 = &ival;

(e) int *pi = &ival; (f) int &rval4 = pi;

(g) int &rval5 = pi*; (h) int &*prval1 = pi;

(i) const int &ival2 = 1; (j) const int &*prval2 = &ival;

Упражнение

Если ли среди нижеследующих операций присваивания ошибочные (используются определения из предыдущего упражнения)?

(a) rval1 = 3.14159;

(b) prval1 = prval2;

(c) prval2 = rval1;

(d) *prval2 = ival2;

Упражнение

Найдите ошибки в приведенных инструкциях:

(a) int ival = 0;

const int *pi = 0;

const int &ri = 0;

(b) pi = &ival; ri = &ival; pi = &rval;

Взаимосвязь массивов и указателей

Если мы имеем определение массива:

int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21 };

то что означает простое указание его имени в программе?

ia;

Использование идентификатора массива в программе эквивалентно указанию адреса его первого элемента:

ia;

&ia[0]

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

// оба выражения возвращают первый элемент

*ia;

ia[0];

Чтобы взять адрес второго элемента массива, мы должны написать:

&ia[1];

Как мы уже упоминали раньше, выражение

ia+1;

также дает адрес второго элемента массива. Соответственно, его значение дают нам следующие два способа:

*(ia+1);

ia[1];

Отметим разницу в выражениях:

*ia+1

и

*(ia+1);

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

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

#include <iostream>

int main()

{

int ia[9] = { 0, 1, 1, 2, 3, 5, 8, 13, 21 };

int *pbegin = ia;

int *pend = ia + 9;

while ( pbegin != pend ) {

cout << *pbegin <<;

++pbegin;

}

}

Указатель pbegin инициализируется адресом первого элемента массива. Каждый проход по циклу увеличивает этот указатель на 1, что означает смещение его на следующий элемент. Как понять, где остановиться? В нашем примере мы определили второй указатель pend и инициализировали его адресом, следующим за последним элементом массива ia. Как только значение pbegin станет равным pend, мы узнаем, что массив кончился. Перепишем эту программу так, чтобы начало и конец массива передавались параметрами в некую обобщенную функцию, которая умеет печатать массив любого размера:

#inc1ude <iostream>

void ia_print( int *pbegin, int *pend )

{ while ( pbegin != pend ) { cout << *pbegin << ' '; ++pbegin; } }

int main() { int ia[9] = { 0, 1, 1, 2, 3, 5, 8, 13, 21 }; ia_print( ia, ia + 9 ); }

Наша функция стала более универсальной, однако, она умеет работать только с массивами типа int. Есть способ снять и это ограничение: преобразовать данную функцию в шаблон

#inc1ude <iostream>

template <c1ass e1emType>

void print( elemType *pbegin, elemType *pend )

{

while ( pbegin != pend ) {

cout << *pbegin << ' ';

++pbegin;

}

}

Теперь мы можем вызывать нашу функцию print() для печати массивов любого типа:

int main()

{

int ia[9] = { 0, 1, 1, 2, 3, 5, 8, 13, 21 };

double da[4] = { 3.14, 6.28, 12.56, 25.12 };

string sa[3] = { "piglet", "eeyore", "pooh" };

print( ia, ia+9 ); print( da, da+4 ); print( sa, sa+3 ); }

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

#include <a1gorithm>

int main()

{

int ia[6] = { 107, 28, 3, 47, 104, 76 };

string sa[3] = { "piglet", "eeyore", "pooh" };

sort( ia, ia+6 ); sort( sa, sa+3 ); };