3.4.1. Встроенный строковый типКак уже было сказано, встроенный строковый тип перешел к С++ по наследству от С. Строка символов хранится в памяти как массив, и доступ к ней осуществляется при помощи указателя типа char*. Стандартная библиотека С предоставляет набор функций для манипулирования строками. Например: // возвращает длину строки int strlen( const char* ); Стандартная библиотека С является частью библиотеки С++. Для ее использования мы должны включить заголовочный файл: #include <cstring> Указатель на char, с помощью которого мы обращаемся к строке, указывает на соответствующий строке массив символов. Даже когда мы пишем строковый литерал, например const char *st = "Цена бутылки вина\n"; компилятор помещает все символы строки в массив и затем присваивает st адрес
первого элемента массива. Как можно работать со строкой, используя такой указатель? while (*st++ ) { ... } st разыменовывается, и получившееся значение проверяется на истинность. Любое
отличное от нуля значение считается истинным, и, следовательно, цикл заканчивается,
когда будет достигнут символ с кодом 0. Операция инкремента ++ прибавляет 1
к указателю st и таким образом сдвигает его к следующему символу. int string_length( const char *st ) { int cnt = 0; if ( st ) while ( *st++ ) ++cnt; return cnt; } Строка встроенного типа может считаться пустой в двух случаях: если указатель на строку имеет нулевое значение (тогда у нас вообще нет никакой строки) или указывает на массив, состоящий из одного нулевого символа (то есть на строку, не содержащую ни одного значимого символа). // pc1 не адресует никакого массива символов char *pc1 = 0; // pc2 адресует нулевой символ const char *pc2 = ""; Для начинающего программиста использование строк встроенного типа чревато ошибками из-за слишком низкого уровня реализации и невозможности обойтись без адресной арифметики. Ниже мы покажем некоторые типичные погрешности, допускаемые новичками. Задача проста: вычислить длину строки. Первая версия неверна. Исправьте ее. #include <iostream> const char *st = "Цена бутылки вина\n"; int main() { В этой версии указатель st не разыменовывается. Следовательно, на равенство
0 проверяется не символ, на который указывает st, а сам указатель. Поскольку
изначально этот указатель имел ненулевое значение (адрес строки), то он никогда
не станет равным нулю, и цикл будет выполняться бесконечно. #include <iostream> const char *st = "Цена бутылки вина\n"; int main() Ошибка состоит в том, что после завершения цикла указатель st адресует не исходный
символьный литерал, а символ, расположенный в памяти после завершающего нуля
этого литерала. В этом месте может находиться что угодно, и выводом программы
будет случайная последовательность символов. st = st – len; cout << len << ": " << st; Теперь наша программа выдает что-то осмысленное, но не до конца. Ответ выглядит так: 18: ена бутылки вина Мы забыли учесть, что заключительный нулевой символ не был включен в подсчитанную длину. st должен быть смещен на длину строки плюс 1. Вот, наконец, правильный оператор: st = st – len - 1; а вот и и правильный результат: 18: Цена бутылки вина Однако нельзя сказать, что наша программа выглядит элегантно. Оператор st = st – len - 1; добавлен для того, чтобы исправить ошибку, допущенную на раннем этапе проектирования программы, – непосредственное увеличение указателя st. Этот оператор не вписывается в логику программы, и код теперь трудно понять. Исправления такого рода часто называют заплатками – нечто, призванное заткнуть дыру в существующей программе. Гораздо лучшим решением было бы пересмотреть логику. Одним из вариантов в нашем случае может быть определение второго указателя, инициализированного значением st: const char *p = st; Теперь p можно использовать в цикле вычисления длины, оставив значение st неизменным: while ( *p++ )Назад Вперед Содержание |
2012-09-15 20:53:08 allegory Для разнобразия: еще несколько вариантов вычисления длины строки в С++: http://hashcode.ru/questions/117559 Оставить комментарий: |