Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
A.doc
Скачиваний:
36
Добавлен:
09.04.2015
Размер:
5.6 Mб
Скачать

188 Глава 4

Другими словами, инкремент и декремент указателя работает в терминах типа объекта, на который он указывает. Увеличение на единицу указателя на long изме- няет его содержимое на адрес следующего long, то есть увеличивает его адрес на че- тыре. Аналогично, инкремент указателя на short на единицу увеличивает значение адреса на два. Более распространенная нотация для увеличения указателя использует операцию инкремента. Например:

Это эквивалентно форме +=, к тому же более часто применяется. Однако я исполь- зовал форму +=, дабы подчеркнуть, что хотя обычно значение инкремента равно еди- нице, эффект от его применения к указателю выражается в увеличении адреса боль- ше чем на единицу, за исключением случая указателя на char.

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

Вы можете, конечно, разыменовать указатель, к которому применено арифмети- ческое действие (а иначе в нем не было бы особого смысла). Например, если предпо- ложить, что pdata все еще указывает на data [2], то оператор:

эквивалентен следующему:

Когда вы хотите разыменовать указатель после увеличения адреса, который он со- держит, скобки необходимы, поскольку приоритет операции разыменования выше, чем приоритет арифметических операций + или -. Если вы напишете выражение *pdata + 1 вместо * (pdata + 1), это добавит единицу к значению, находящемуся по адресу, хранящемуся в pdata, что эквивалентно выполнению data [2] + 1. Поскольку это не lvalue, его применение в предыдущем операторе присваивания заставит ком- пилятор сгенерировать сообщение об ошибке.

Вы можете использовать имя массива, как если бы это был указатель, для обра- щения к его элементам. Если у вас есть одномерный массив вроде того, что раньше, объявленный, как:

то, применив нотацию указателя, вы можете сослаться на элемент data [3], напри- мер, так: * (data + 3). Этот вид нотации может применяться совершенно свободно, так что для доступа к элементам data [ 0 ], data [ 1 ], data [ 2 ] вы можете писать *data, * (data + 1), * (data+2) и так далее.

Испытать этот аспект адресации массивов можно на примере следующей програм- мы, которая находит простые числа (простое число — то, которое делится только на себя и на единицу).

Массивы, строки и указатели 189

Если скомпилировать и запустить этот пример, то получится следующий вывод:

190 Глава 4

Описание полученных результатов

Здесь присутствуют обычные операторы #include с заголовочным файлом <iostream> для ввода и вывода, а также с <iomanip>, поскольку используются мани- пуляторы потока для установки ширины полей при выводе.

Константа МАХ определяет количество простых чисел, которые нужно получить от программы. Массив primes, в котором сохраняются результаты, инициализирован первыми тремя простыми числами, чтобы было с чего запустить процесс. Вся работа выполняется в двух циклах: внешнем do-while, который указывает следующее прове- ряемое значение и добавляет найденное значение в массив primes, если оно является простым числом, и внутренним циклом for, который в действительности проверяет значение на принадлежность к множеству простых чисел.

Алгоритм цикла for очень прост и основан на том факте, что если число не про- стое, то оно должно делиться на одно из ранее найденных простых — каждое из ко- торых меньше проверяемого, поскольку все числа являются либо простыми, либо произведениями простых. Фактически, нужно проверить только деление на простые числа, меньшие или равные корню квадратному из проверяемого числа, поэтому дан- ный пример еще не настолько эффективен, насколько он мог бы быть.

Этот оператор присваивает переменной found значение 1, если нет остатка от де- ления значения trial на текущее простое число * (primes + i) (напомним, что это эквивалентно primes [i]), и 0 — в противном случае. Оператор if прерывает цикл for, если found равно 1, поскольку число-кандидат в trial в этом случае не является простым.

После завершения цикла for (по любой причине) необходимо решить, является ли текущее значение trial простым. Это определяется значением индикаторной пе- ременной found.

Если trial действительно содержит простое число, этот оператор сохраняет его значение в primes [count], после чего увеличивает count с помощью постфиксной операции инкремента.

После того, как найдено МАХ простых чисел, они выводятся в поле шириной 10 символов, по 5 в строке, в результате выполнения такого оператора:

Это начинает новую строку, когда i получает значения 0, 5, 10 и так далее.

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

Массивы, строки и указатели 191

Вот пример типичного вывода этого примера:

Описание полученных результатов

Здесь программа работает с указателем pbuf fer, а не с именем массива buffer. Не нужна переменная count, поскольку указатель увеличивается в цикле while, пока не найдет \0. Когда обнаруживается символ \0, pbuf fer содержит адрес его положе- ния в строке. Счетчик количества символов строки, таким образом, вычисляется, как разница между адресом, записанным в pbuf fer, и адресом начала массива, который обозначен buffer.

Вы могли бы также выполнять инкремент указателя в цикле следующим образом:

Этот цикл не содержит в себе никаких операторов, а только проверочное условие. Это должно работать адекватно, за исключением того факта, что значение счетчика увеличивается после достижения \0, поэтому адрес будет на единицу больше, чем по- следняя позиция в строке. Поэтому в данном случае количество символов в строке должно быть вычислено как pbuf fer — buffer — 1.

Обратите внимание, что здесь вы не можете применять имя массива так же, как ис- пользуете указатель. Выражение buf fer++ совершенно неправильно, поскольку нель- зя модифицировать значение адреса, которое представляет имя массива. Даже несмо- тря на то, что вы можете использовать имя массива в выражениях вместо указателя, все же это — не указатель, поскольку адрес, который оно представляет, фиксирован.

Применение указателей с многомерными массивами

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