3.9.2. Взаимосвязь массивов и указателейЕсли мы имеем определение массива: 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); Операция разыменования имеет более высокий приоритет, чем операция
сложения (о приоритетах операций говорится в разделе 4.13).
Поэтому первое выражение сначала разыменовывает переменную 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 ) { Наша функция стала более универсальной, однако, она умеет работать только с массивами типа int. Есть способ снять и это ограничение: преобразовать данную функцию в шаблон (шаблоны были вкратце представлены в разделе 2.5): #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 ); Мы написали обобщенную функцию. Стандартная библиотека предоставляет набор обобщенных алгоритмов (мы уже упоминали об этом в разделе 3.4), реализованных подобным образом. Параметрами таких функций являются указатели на начало и конец массива, с которым они производят определенные действия. Вот, например, как выглядят вызовы обобщенного алгоритма сортировки: #include <a1gorithm> int main() { int ia[6] = { 107, 28, 3, 47, 104, 76 }; string sa[3] = { "piglet", "eeyore", "pooh" }; sort( ia, ia+6 ); (Мы подробно остановимся на обобщенных алгоритмах в главе 12; в Приложении
будут приведены примеры их использования.) Содержание |
Нет комментариев. Оставить комментарий: |