
Основы алгоритмизации (ОАП) / Теория / Строки
.pdf
Главная
СТРОКИ
Для представления символьной информации можно использовать символы, символьные переменные и символьные константы.
В С++ поддерживаются два типа строк – встроенный тип, доставшийся от С, и класс string из стандартной библиотеки С++. Класс string предоставляет гораздо больше возможностей и поэтому удобнее в применении.
Встроенный строковый тип
Встроенный строковый тип перешел в С++ от С. Строка символов хранится в памяти как массив, и доступ к ней осуществляется при помощи указателя типа char*. Количество элементов в таком массиве на один элемент больше, чем изображение строки, т.к. в конец строки добавлен '\0' (нулевой байт или нуль-терминатор:
АА \0
„A‟ “A”
символ(1 байт) |
строка (2 байта) |
Объявление и инициализация строк
Поместить строку в массив можно либо при вводе, либо с помощью инициализаций:
char str1[] = "STRING";
char str2[20] = { 'S','t','r','i','n','g','\0' }; const char *str3 = "STRING\n";
char str4[20];
cin >> str4;
//строка не должна превышать 19 симв. + 0 символ
Символьные строки хранятся в виде массивов, поэтому их нельзя приравнивать и сравнивать с помощью операций = и ==.
Типичной ошибкой является невыделение достаточного места в массиве символов для хранения нулевого символа, завершающего строку.
Строку можно присвоить символьному массиву, используя операцию cin. В некоторых случая желательно вводить в массив полную строку текста. С этой целью
1

можно использовать функцию С++ cin.getline. Она требует три аргумента – массив символов, в котором должна храниться строка текста, длина и символ-ограничитель:
char str1[80]; cin.getline(str1, 80, '\n');
Функция прекращает считывать символы если встречается символ-ограничитель '\n' и если количество считанных символов оказывается на один меньше, чем указано во-втором аргументе. Третий аргумент имеет '\n' в качестве значения по умолчанию, так что в вызове функции его можно опустить.
Согласно общепринятым стандартом ASCII установлено соответствие между символами и кодами. Клавиатура (совместно с драйвером) кодирует нажатие любой клавиши с учетом регистровых и управляющих клавиш в соответствующий ей код (прил. 1 содержит список символьных кодов ASCII). Например:
' ' |
- |
0x20, |
'B' |
- |
0x42, |
'*' |
- |
0x2A, |
'Y' |
- |
0x59, |
Манипуляции со строками и символами на самом деле подразумевают манипуляции с соответствующими численными кодами, а не с самими символами. Это объясняет взаимозаменяемость символов и малых целых в С++. Так как имеет смысл говорить, что один численный код больше, меньше или равен другому численному коду, можно сопоставлять различные строки и символы друг с другом.
Некоторые программы и стандартные функции обработки символов и строк используют тот факт, что цифры, прописные и строчные (маленькие и большие) латинские буквы имеют упорядоченные по возрастанию значения кодов:
'0' - '9' 0x30 - 0x39 'A' - 'Z' 0x41 - 0x5A 'a' - 'z' 0x61 - 0x7A
Тогда, для получения символа десятичной цифры из значения целой переменной, лежащей в диапазоне 0…9, а также значения целой переменной из символа десятичной цифры можно:
int |
n = 5; |
char |
c; |
c = n + '0';
if (c >= '0' && c <= '9') n = c - '0';
Для преобразования строчной латинской буквы в прописную необходимо:
char c;
if (c >='a' && c <='z') c = c - 'a' + 'A';
Типичной ошибкой является обработка одного символа как строки.
2

Работа со строкой
Обычно для перебора символов строки применяется адресная арифметика. Поскольку строка всегда заканчивается нулевым символом, можно увеличивать указатель на 1, пока очередным символом не станет нуль. Например:
while (*str1++ ) { ... }
str1 разыменовывается, и получившееся значение проверяется на истинность. Любое отличное от нуля значение считается истинным, и, следовательно, цикл заканчивается, когда будет достигнут символ с кодом 0. Операция инкремента ++ прибавляет 1 к указателю str1 и таким образом сдвигает его к следующему символу.
Подсчет длины строки может выглядеть следующим образом:
char st[] = "STRING";; int cnt = 0;
if ( st )
while ( *st++ ) ++cnt;
Поскольку указатель может содержать нулевое значение (ни на что не указывать), перед операцией разыменования его следует проверять.
Строка встроенного типа может считаться пустой в двух случаях: если указатель на строку имеет нулевое значение (строки нет) или указывает на массив, состоящий из одного нулевого символа (строка, не содержит ни одного значимого символа).
//pstr1 не адресует массива символов char *pstr1 = 0;
//pstr2 адресует нулевой символ const char *pstr2 = "";
При работе со строкой можно, также как и в массивах, использовать нотацию индексов:
for (int i = 0; (s1[i] = s2[i])!= '\0'; i++); //
а также нотацию указателей:
for (; (*s1 = *s2) != '\0'; s1++, s2++); // копирование
Использование строк встроенного типа чревато ошибками из-за слишком низкого уровня реализации и невозможности обойтись без адресной арифметики. Рассмотрим типичные ошибки. Например:
const char *str = "STRING\n"; int len = 0;
while ( str++ ) ++len; //ошибка,str не разыменовывается и изменяется
Указатель str не разыменовывается, следовательно, на равенство 0 проверяется не
3

символ, а сам указатель. Поскольку изначально этот указатель имел ненулевое значение (адрес строки), то он никогда не станет равным нулю, и цикл будет выполняться бесконечно.
Поскольку строка представляет собой последовательность символов, большинство программ, обрабатывающих строки, используют последовательный или посимвольный просмотр строки. Если же в процессе обработки строки предполагается изменение ее содержимого, то проще всего (но не всегда эффективно) организовать его в виде посимвольного переписывания входной строки в выходную. При этом нужно помнить, что каждой строке требуется отдельный индекс, если для входной строки он может изменяться в заголовке цикла посимвольного просмотра, то для выходной строки он меняется только в моменты добавления очередного символа. Кроме того, не нужно забывать «закрывать» выходную строку символом конца строки. В качестве примера рассмотрим пример удаления лишних пробелов из строки:
сhar str1[] = "STR ING"; сhar str2[10];
int i,j;
for (j = 0, i = 0; str1[i] != 0; i++) // Посимвольный просмотр строки
{
if (str1[i] != ' ') // Текущий символ – не пробел
{
if (i!=0 && str1[i-1] == |
' ')// |
Первый в |
слове - |
str2[j++] = ' '; |
// |
добавить |
пробел |
str2[j++] = str1[i]; |
// Перенести символ слова |
||
} |
// в выходную строку |
}
str2[j] = 0;
Рассмотрим еще один пример проверки правильности расстановки круглых скобок в строке:
4

char s[256];
int i, c; // с переменнаясчетчик cout << "Введите строку"; gets(s); // вводим строку
for(c = i = 0; s[i] != 0; i++)
{
if(s[i] == '(') // если скобка открывающая c++; // увеличить счетчик
if(s[i] == ')') // если скобка закрывающа c--; // уменьшить счетчик
}
if(!c)
//если с = 0, кол-во открывающих // и закрывающих скобок равно
cout << "Текст сбалансирован по скобкам\n";
else
cout << "Баланса скобок нет\n";
Функции работы со строками
Стандартная библиотека С предоставляет набор функций для манипулирования строками. Стандартная библиотека С является частью библиотеки С++. Для ее использования мы должны включить заголовочный файл #include <cstring>. Функции приведены в табл. 1.
Таблица 1
|
Набор функций манипулирования строками |
|
|
Функция |
Прототип и краткое описание функции |
strcmp |
int strcmp(const char *str1, const char *str2); |
|
Сравнивает строки str1 и str2. Если str1 < str2, то результат |
|
отрицательный, если str1 = str2, то результат равен 0, если str1 > |
|
str2, то результат положительный |
strcpy |
char* strcpy(char*s1, const char *s2); |
|
Копирует байты из строки s1 в строку s2 |
strdup |
char *strdup (const char *str); |
|
Выделяет память и переносит в нее копию строки str. |
strlen |
int strlen (const char *str); |
|
Вычисляет длину строки str |
strncat |
char *strncat(char *s1, const char *s2, int |
|
kol); |
|
Приписывает kol символов строки s1 к строке s2 |
strncpy |
char *strncpy(char *s1, const char *s2, int |
|
kol); |
|
Копирует kol символов строки s1 в строку s2 |
strnset |
char *strnset(char *str, int c, int kol); |
|
Заменяет первые kol символов строки s1 символом с |
5
atoi |
int atoi(char *str); |
|
|
Преобразует строку в целое |
|
atof |
float atof(char *str); |
|
Преобразует строку в число с плавающей точкой |
||
|
Строки при передаче в функцию в качестве фактических параметров могут быть определены либо как одномерные массивы типа char[], либо как указатели типа char*. В отличие от массивов, в этом случае нет необходимости явно указывать длину строки.
Для указателя с типом указуемой переменной char допускаются различные интерпретации: указатель на отдельный байт; указатель на область памяти – массив байтов; указатель на отдельный символ; указатель на массив символов.
6