Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 30
Текст из файла (страница 30)
Благодаря этому в строках можно хранить символ двойной кавычки и обратной косой черты, Самым распространенным символом такого типа является символ перехода на новую строку ('~п'). Например: соиг« "звуковой сигнал в конце сообщения ~а~п', Специальный символ '~а' из набора ЛЗСП означает ВЕ(. (звонок); прц его выводе раздается звуковой сигнал. Нельзя получить перевод строки, чпо-настоящему» переведя строку: "это не строка, а синтаксическая ошибка" 5.3. Указатели на массивы В С-»» указатели и массивы тесно связаны. Имя гпассива можно использовать в каче- стве указателя на его первый элемент. Например: 1пгоД = (1,2, 3,4); т1'р1.=о; // укозитель на первый элемент // (неявное преобразованне1 // указатель на первый злеменгп // указатель на элемент, следующис1 за последним 1пг' р2 = йи(01, сп1* рд = 8 о(4); /(дивные строки можно разделять символами-разделителями, например, чтобы сде- лать код более читабельным.
Строки сИаг а1рИа[] = 'аЬсс1еЯИ11И(тпордгзгиоиауг' АВСГЗЕЕОНИИМ1У ОРЕ/кЬ Т11И Тн1ТХ"; компилятор объединит в одну строку, поэтому а1рЬа можно было инициализировать и следующей строкой: 'аИМеЯИ ЦИ!тпорргз1ииьэкугАОСЮЕЕОН111(ьМНОР9ЯБТ1/ИтгХУ2", Можно включать в строку нулевои символ, цо большинство программ не догадаются, что после него есть еще что-то. Например, строка "Йенс',ОООМунк' будет интерпре- тироваться как "Йенс" такими функциямн стандартной библиотеки, как з1гсрд 'и цли з1г(егг 'и (см.
З 20.4.1). Строка с префиксом Е. например Е"апдз1", является строкой символов из расши- ренного набора Я 4.3, В В.З.З). Бе тип сопз1шсйае 1П. Глава 5. Указатели, массивы и структуры и.ли графически 'и0 2хюД 4 Гарантируется осмысленность значения указателя на элемент, следуюгдий за последним элементом массива, Это важно для многих алгоритмов Я 2.7.2, Э 18.3). Впрочем, ввиду того, что такой указатель на самом деле пе указывает ни на какой элемент массива, его нельзя использовать нн для чтения, ни для записи. 1'езультат получения адреса элемента массива, предшествующего первому, не определен, и такой операции следует избегать. На некоторых машинах память под массивы вгяделяется с самого начала адресного пространства, поэтому «адреса элемента, предшествующего первому» возможно просто не существует. 11еявное преобразование имени массива в указатель на его первый э не»сент широко используется в вызовах функций С.
Например: еягегп гС бп!в!г!еп(сопя!спас='Ь /!находи~лаяв «в!ппдб» ооЫЛ ( айаг оЦ = Анна-Мария"; сйаг*р = о; в!с!еп !р!, в! !еп !о); о=р; // неявное преобразование гбагЦ в сваг* ~7 неявное преобразовиние г1~а Ц в г!гас* /г гниибка: нельзя пригваивапгь массиву 5.3.1. Доступ к элементам массива Эффективный и элегантный доступ к массивам (и подобным структурам данных) является ключевым моментом для многих алгоритмов (см. ч 8.8 и главу 18). Доступ к элементам массива может осуществляться либо при помощи указателя на массив и индекса, либо через указатель на элемент массива. Рассмотрим пример прохода по строке с использованием индекса: При обоих вызовах стандартной библиотечной функции в!г!еп (! передается одно и то же значение.
Загвоздка в том, что невозможно избежать неявного преобразования типов. Другими словами. невозможно обьявить какую-нибудь функцию таким образом, чтобы прн ее вызове массив о копировался. К счастью, не существует ци явного, нн неявного преобразования указателя в массив. Неявное преобразование массива в указатель при вызове функции приводит к потере информации о размере массива.
Но вызываемая функция должна каким-либо образом определить этот размер, чтобы выполнять осмысленные действия. Как и другие функции С из стандартной библиотеки, принимающие укаьагель на строку символов, в!г!еп (! считает, что ее аргумент, строка завершается нулем; в!г!еп 0 возвращает количество символов в строке, вплоть до завершающего нуля, но не считая его. Все это — вопросы достаточно низкого уровня. Типы оес!ог (5 16.3) н в!г!по (глава 20) стандартной библиотеки не страдают подобными недостатками.
5.3. Указатели на массивы вой (сваг о[]] ( 1ог (!л! !=О; оЯ!ыО; !4-з( изе (о[!]]; Это эквивалентно следующему примеру, где используется указатель: ооИ Тр (ейаг о[]( ( (ог (сваг' р=о; *р!=0; рзз-] изе (*р], Префиксный оператор " означает разыменование, поэтому *р есть символ, на которьш указывает р. Оператор++ увеличивает значение указателя таким образом, что он указывает на следующий элемент массива.
Не существует внутренних причин, по которым один вариант был бы быстрее другого. Современный компилятор должен сгенерировать тождественный код для обоих примеров (см. ч 5.9[8]). Программисты люгут выбирать между этими вариантами, исходя из логических илп эстетических соображений. Результат прнмененця арифметического оператора +, —, ++ плн — к указателю зависит от типа объекта, на который ссылается указатель. Если к указателю р типа. Т' применяется арифметическая операция, предполагается, что р указывает на элемент массива типа Т; р+1 указывает на следуюгпий алемент массива, а р-1 — на предыдущий. То есть целое значение рз1 будет на з!хео1 (Т] больше, чем целое значение р.
Например, результатом выполнения №!лс!иНе с!оз!геат> !л! та(л (] ( сл ! и![10], з1шг! из[10]; зЫ .сои! «М([0] « ' ' «йо([!] « '~л'; з!с(:мои ! «с из[0] « ' ' «Мз[1] « ",л'; будет Ох7Щае10 Ох707аес!с Ох7ЯУае14 Ох 71)Таес(е при использовании принятой по умолчанию шестнадцатеричной формы записи указателей. Пример демонстрирует, что в моей реализации з!хель(з]зог!] равен 3, а з!хеоТ (сл!] равен 4.
Вычитание указателей друг из друга определено только в том случае, если оба указателя указывают на элементы одного н того же массива (хотя язык не позволяет быстро проверить, так ли это). Резучьтатом вычитания одного указателя из другого будет количество элементов массива (целое число) между этими указателями. К указателю можно прибавлять целое и вычитать из него целое; в обоих случаях, результатом будет указатель.
Если полученный таким образом указатель не указывает па элемент того же массива (или на элемент, следуюьций за последним), что и исходный, то результат его использования не определен. Например: Глава 5. Указатели, массивы и структуры !34 оо1с)1 () ( 1псо1[10). 1пг о2[10]; !1'11=2 О резрмьтат не определен 1п111 = с о1[5] — с.о1[8), 1пг 12 = с о1[5] — йи 2[3], 1пг"р1=ог -г; //р1 = 8,иг[2] пг*рг = г - г, 1'1' 'р2 не определен ) Обычно пет необходимости в использовании относительно сложной арифметики указателей, лу ппе ее вообще избегать.
Сложение указателей смысла не имеет и поэтому запрещено. Массивы не самодостаточны в том смысле, что пе гарантируется хранение информации о количестве элементов вместе с самим массивом. Предполагается. что для просмотра элементов массива в случаях. когда в массиве нет ограни щвающего символа (как для строк), необходимо каким-либо образом указать размер явно.
Например: ооЩр (слог и[), ипвгяпес( т1з1ее', )ог [ии 1=0; 1кзгее, 1-с) изе (и[1)); сопв11п1Ж = 7; айаг о 2[1У]; гог (т1 1=.0; 1<йС, 1+к-) иве (ог[1]), ) Обратите внимание, что в большинствереализаций С+ отсутствует проверка диапа- зонадля массивов. Таков традиционный низкоуровневый подход к массивам. Более со- вершенное понятие массива можно реализоват* при помощи классов [снь 5 3 7 ) ). 5.4. Константы со пег т1 тос(е1 = 90; 77 тоде1 являептся кон~ тантой сопз1т1о[) = ( 1, 2, 8, 4); 1'Г' все и[1] являются константал~и сопвгт1х; О ошибка: нет инициалс~загпора Объявление чего-либо в качестве сопз1 гарантирует, что в текущей области видимос- ти его значение не изменится: В Сл -- введена ко~щепция определяемых пользователем констант [сопз1) для указания на то, что значение нельзя изменить непосредственно.
Это может быть полезно в нескольких отношениях. Например, многие объекты не меняются после инициализации; использование символических констант приводит к более удобному в сопровождении коду, чем применение литералов непосредственно в тексте программы; указатели часто используются только для чтения, но не для записи; большинство аргументов функций читаются, но не перезапнсываются. Чтобы объявить объект константой, в объявление нужно добавить ключевос слово сопвй Так как константе нельзя присваивать значения, она должна быть пннццализпрована.
Например: 135 5 4 Константы оо!с! /() ( тоа!е! = 200, о[2).н-, ) // от иоки // ошибка Отметьте, что сопя! модифицирует тип, то есть сопя! ограничивает возможное использование объекта, но не указывает способ размещения константного объекта. Например. иои4 д (сопл! Х' р( ( //здесь нельзя изл~енать 'р ооиул() ( Хэа(, //оа! иожнояенять и(зоа1), //- ) В зависимости от степени изощренности, компилятор может несколькими способами воспользоваться константностью обьекта. Например, инициализатор константы часто (но це всегда) является константным выражением (5 В.б); если это так, его можно вычислить в момент компиляции. Более того, если компилятору известны всс случаи непользования константы, он может не выделять под нее память. Например: сопя! !и! с! = 1, со !!л!сг=г, сопя! и! сЗ = ту ~(З), ех!егп солз! !и! с4, соня! !л!" р = йс2, //значение сЗ не известно во врелья колптяции // значение с4 не известно во вреял колл иляцин // необлодило выделить память под с2 сопед!лги = 42, сопя! ьп! Ь = 09, Ирц наличии таких объявлений компилятор знает значения с1 и с2, поэтому их можно использовать в константных выражениях.
Так как значения сЗ и с4 неизвестны во время компиляции (при использовании только информации, доступной в даннои единице компиляции; см. э 9.1), для ннх должна быть выделена память. Так как берется адрес с2 (и црелположитсльно где-то используется), должна быть выделена память под с2. Простым и типичным использованием константы является тот случай, когда значение константы известно во время компиляции и под нее не требуется выделение памяти. Примером является с1. Ключевое слово ех!егп означает, что с4 определена в другом месте (э' 9.2). Как правило, для массива констант требуется выделение памяти, так как, в общем случае, компилятор не в состоянии определить, к какому элементу массива происходит доступ в выра;кепиях.