- •6 Глава 1
- •12 Глава 1
- •14 Глава 1
- •16 Глава 1
- •18 Глава 1
- •20 Глава 1
- •22 Глава 1
- •24 Глава 1
- •26 Глава 1
- •31 Глава 1
- •34 Глава 2
- •36 Глава 2
- •Puc. 2.4. Дополнительные опции консольного приложения Win32
- •38 Глава 2
- •40 Глава 2
- •42 Глава 2
- •44 Глава 2
- •48 Глава 2
- •50 Глава 2
- •52 Глава 2
- •54 Глава 2
- •56 Глава 2
- •58 Глава 2
- •60 Глава 2
- •62 Глава 2
- •64 Глава 2
- •66 Глава 2
- •68 Глава 2
- •70 Глава 2
- •74 Глава 2
- •76 Глава 2
- •79 Глава 2
- •82 Глава 2
- •84 Глава 2
- •86 Глава 2
- •88 Глава 2
- •92 Глава 2
- •94 Глава 2
- •96 Глава 2
- •98 Глава 2
- •103 Глава 2
- •105 Глава 2
- •107 Глава 2
- •110 Глава 2
- •115 Глава 3
- •119 Глава 3
- •121 Глава 3
- •123 Глава 3
- •125 Глава 3
- •129 Глава 3
- •131 Глава 3
- •133 Глава 3
- •139 Глава 3
- •141 Глава 3
- •143 Глава 3
- •145 Глава 3
- •148 Глава 3
- •150 Глава 3
- •155 Глава 3
- •165 Глава 4
- •168 Глава 4
- •170 Глава 4
- •173 Глава 4
- •175 Глава 4
- •178 Глава 4
- •184 Глава 4
- •186 Глава 4
- •188 Глава 4
- •190 Глава 4
- •192 Глава 4
- •194 Глава 4
- •198 Глава 4
- •201 Глава 5
- •203 Глава 5
- •205 Глава 5
- •207 Глава 5
- •213 Глава 5
- •217 Глава 5
- •219 Глава 5
- •221 Глава 5
- •223 Глава 5
- •225 Глава 5
- •227 Глава 5
- •232 Глава 5
- •234 Глава 5
- •236 Глава 5
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) и так далее.
Испытать этот аспект адресации массивов можно на примере следующей програм- мы, которая находит простые числа (простое число — то, которое делится только на себя и на единицу).
Массивы,
строки и указатели
Если скомпилировать и запустить этот пример, то получится следующий вывод:
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 и так далее.
Чтобы увидеть, как обрабатываются строки в нотации указателей, можно напи- сать версию программы, рассмотренной ранее, которая предназначалась для подсче- та символов в строке:
Массивы,
строки
и
указатели
Вот пример типичного вывода этого примера:
Описание полученных результатов
Здесь программа работает с указателем pbuf fer, а не с именем массива buffer. Не нужна переменная count, поскольку указатель увеличивается в цикле while, пока не найдет \0. Когда обнаруживается символ \0, pbuf fer содержит адрес его положе- ния в строке. Счетчик количества символов строки, таким образом, вычисляется, как разница между адресом, записанным в pbuf fer, и адресом начала массива, который обозначен buffer.
Вы могли бы также выполнять инкремент указателя в цикле следующим образом:
Этот цикл не содержит в себе никаких операторов, а только проверочное условие. Это должно работать адекватно, за исключением того факта, что значение счетчика увеличивается после достижения \0, поэтому адрес будет на единицу больше, чем по- следняя позиция в строке. Поэтому в данном случае количество символов в строке должно быть вычислено как pbuf fer — buffer — 1.
Обратите внимание, что здесь вы не можете применять имя массива так же, как ис- пользуете указатель. Выражение buf fer++ совершенно неправильно, поскольку нель- зя модифицировать значение адреса, которое представляет имя массива. Даже несмо- тря на то, что вы можете использовать имя массива в выражениях вместо указателя, все же это — не указатель, поскольку адрес, который оно представляет, фиксирован.
Применение указателей с многомерными массивами
Применение указателя для хранения адреса одномерного массива относительно просто, но когда речь идет о многомерных массивах, все несколько усложняется. Если вы не собираетесь делать это, можете пропустить настоящий раздел, так как он немного запутан; однако если у вас есть предварительный опыт использования языка С, на него стоит взглянуть.