<<
>>

Массивы и указатели в языках С и С++

Операция разыменования указателя p в языке С обозначается так *p. Это одноместная операция. Применяя ее к указателю, получаем объект, на который указатель ссылается [14, 18, 30, 34].

Объявления же указателей в языке С имеют вид: int *pa; float *pb;

Форма такого объявления задумывалась как мнемоническая — специально для облегчения его понимания и использования. Первое объявление означает, что выражение *pa имеет тип int. Иными словами, результат разыменования указателя pa имеет тип int.

После обработки этих объявлений указатель pa может хранить адреса целых переменных, а указатель pb — адреса вещественных переменных.

Использование массивов и указателей в С тесно связано. Фактически имя массива А является указателем на его начальный, нулевой элемент A[0] . Таким образом, использование указателей для доступа к обычным массивам, размещенным в статической памяти, здесь считается обычным приемом.

Мало того, разрешена (и приветствуется) адресная арифметика, то есть манипулирование адресами, находящимися в указателях.

Рабочим инструментом адресной арифметики считается адресное выражение.

Адресное выражение — это выражение, значением которого является адрес элемента массива (или какой-то ячейки памяти). Так, адресное выражение A + 1 (значение указателя А плюс единица) указывает на элемент массива A[1], а A + i указывает на A[i]. Все это приводит к очень интересным возможностям.

Приведем иллюстрирующий пример. Если имеются следующие объявления int i;

int vector [100]; int *ptr;

то после выполнения оператора присваивания ptr = vector;

292

Глава 11. Указатели

имя указателя ptr становится эквивалентно имени массива vector и можно сделать следующие заключения:

? имя ptr[i] обозначает ту же ячейку массива, что и vector[i];

? разыменование адресного выражения *(ptr + i) дает значение, которое одновременно является r-значением индексированной переменной vector [i].

Иначе говоря, указатель на массив можно индексировать так, словно он является

именем массива, а имя массива может служить компонентом адресного выражения.

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

Указатель в языке С может обслуживать любую статическую переменную с именем. Речь идет о том, что переменная помимо прямого имени может получить и косвенное имя — адрес, хранящийся в указателе.

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

Например, если объявлена целая переменная с именем х и указатель на целые переменные p int х; int *p;

то после выполнения оператора

p = & x; /* запись адреса переменной х в указатель p */

операторы

*p = *p + 1;

x = x + 1;

считаются эквивалентными.

ПРИМЕЧАНИЕ ------------------------------------------------------

*p в правой части оператора присваивания обозначает значение x, а в левой части — место размещения (адрес) x.

Пример 1. Линейный поиск в массиве с использованием сигнальной метки х может быть описан следующим фрагментом.

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

Массивы и указатели в языках С и С++

293

Теперь рассмотрим возможности языка С по представлению и обработке такой популярной структуры данных, как символьные строки.

Вспомним, что строки в языке С представляются как массивы из символов.

Конец строки маркируется константой EOS, определяемой в виде '\0'.

Например, три символьные строки маша мыла раму

хранятся в «ленте» памяти так, как это изображено на рис. 11.12.

Рис. 11.12. Лента памяти, хранящей три строки

Здесь подразумевается, что каждый символ занимает отдельную ячейку памяти.

Пример 2. Скопируем строку buffer в область памяти start, начиная с ячейки start[next]. Используем два указателя p и q.

Прокомментируем первый оператор программного фрагмента. Когда имя массива (являющееся указателем) связывается индексом, оно превращается в простое имя ячейки массива. Иначе говоря, от имени start взять адрес нельзя (это указатель), а от имени start [next] — можно.

После двух первых операторов p указывает на место, куда должен быть скопирован первый символ, а q указывает на первый элемент массива buffer.

Читаем for ( ; ; ) как «всегда». Операторы между фигурными скобками повторяются до момента выполнения оператора break. Присваивание

*p = *q;

обеспечивает копирование одного символа.

Если это символ EOS (конец строки), тогда цикл завершается с помощью break. В противном случае с помощью постфиксной операции ++ увеличиваются p и q. Они указывают на следующий доступный элемент start и следующий копируемый символ соответственно.

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

Особую роль в С и С++ играют «бестиповые» указатели вида void *, обеспечивающие адресацию объектов любых типов.

Они очень удобны при решении таких задач операционной системы, как управление памятью компьютера. Как правило, здесь идет речь о пересылке порций данных из одного места в другое,

294

Глава 11. Указатели

невзирая на их форматы и внутреннюю структуру. Иными словами, перемещаться должны не числа или строки, а некие байты какой-то информации. Внутреннее содержание и структура «посылок» систему не интересует. Вот такими «неинтересующимися» почтальонами и служат бестиповые указатели. Эти «адресные механизмы» даже при желании не смогли бы выяснить содержание посылок, так как разыменовать бестиповой указатель просто нельзя. Конечно, после прибытия на место назначения данные могут быть расшифрованы, но к этому бестиповые указатели прямого отношения не имеют. Свое дело они уже сделали: сняли все запреты на пересылку.

<< | >>

Еще по теме Массивы и указатели в языках С и С++:

  1. ГЛАВА 5 МЫ ГОВОРИМ НА РАЗНЫХ ЯЗЫКАХ
  2. 18.5. Права и обязанности держателя (обладателя) по работе с массивами персональных данных
  3. УКАЗАТЕЛЬ СОКРАЩЕНИЙ
  4. Алфавитно-предметный указатель
  5. Алфавитно-предметный указатель
  6. Алфавитно-предметный указатель
  7. АЛФАВИТНО-ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ
  8. ИНДЕКС
  9. 18.6. Государственное регулирование работы с персональными данными
  10. Дополнительная литература