В С++ отсутствует специальный тип строк. Строки рассматриваются как массивы символов, оканчивающиеся нулевым символом ('\0'). Строка доступна через указатель на первый символ в строке. Значением строки является адрес ее первого символа. Таким образом, в С++ строка является указателем - указателем на первый символ строки. В этом смысле строки подобны массивам, потому что массив тоже является указателем на свой первый элемент.
Строка может быть объявлена либо как массив символов, либо как переменная типа char*. Каждое из двух приведенных ниже эквивалентных объявлений:
char S[] = "строка";
char *Sp = "строка";
присваивает строковой переменной начальное значение «строка». Первое объявление создает массив из 7 элементов S содержащий символы 'с', 'т', 'р', 'о', 'к', 'а' и '\0'. Второе объявление создает переменную указатель Sp, который указывает на строку с текстом «строка», лежащую где-то в памяти. Но в любом случае число хранимых символов на 1 больше числа значащих символов за счет оконечного нулевого символа.
Доступ к отдельным символам строки осуществляется по индексам, начинающимся с нуля. Например, S[0] и Sp[0] первые символы объявленных выше строк, S[1] и Sp[1] вторые и т.д.
В приведенных объявлениях длина строк определялась автоматически компилятором. Можно объявлять строковые переменные заданной длины. Например, оператор:
char buff[100];
объявляет переменную buff, которая может содержать строку до 99 значащих символов плюс заключительный нулевой символ.
Для обработки строк имеется ряд библиотечных функций. Основные из них:
- strcat - конкатенация (склеивание) двух строк
- strcmp - сравнение двух строк
- strcpy - копирование одной строки в другую
- strstr - поиск в строке заданной подстроки
- strlen - определение длины строки
- strupr - преобразование символов строки к верхнему регистру
- sprintf - построение строки по заданной строке форматирования и списку аргументов и ряд других функций.
Выше было приведено объявление массива символов buff. Как занести в него какой-то текст? Это можно сделать с помощью функции strcpy:
strcpy(buff,"Текст, копируемый в buff");
Эта функция копирует строку, являющуюся ее вторым параметром, в строку, являющуюся первым параметром, и возвращает указатель на результат копирования.
Теперь решим задачу посложнее. Пусть, например, нужно прибавить в конец текста строки S1 текст, хранящийся в строке S2. Это можно сделать с помощью функции strcat:
char S1[20] = "текст 1", S2[10] = "текст 2";
strcat(S1,S2);
Обратите внимание на то, что размер первой строки выбран с запасом, чтобы в ней уместились оба текста. Если не задать в объявлении размер строки, то он определится но присваиваемому ей тексту и в ней не останется места для каких-то добавлений.
Функция strcat прибавляет к тексту строки, указанной ее первом параметром, текст строки, указанной вторым параметром, и возвращает указатель на первую строку. Последнее обстоятельство позволяет делать вложенные вызовы strcat, если надо склеить несколько текстов.
Давайте несколько усложним задачу. Пусть нужно оставить в неприкосновенности обе строки, а в третьей строке S надо получить склеенные тексты строк S1 и S2, разделенные символом пробела. Это можно сделать следующими операторами:
char *S1 = "текст 1", *S2 = "текст 2", S[20];
strcat(strcat(strcat(S,S1)," "),S2);
Самый внутренний вызов strcat склеивает пустую строку S и строку S1, Он возвращает указатель на S и, значит, следующий вызов strcat склеивает текст, появившийся в S, со строковой константой, содержащей символ пробела. Функция strcat опять возвращает указатель на S и последний внешний вызов strcat добавляет к уже сформированной строке текст строки S2.
Приведенный код будет работать, если есть уверенность, что сначала текст в S отсутствует. Чтобы не зависеть от исходного текста в S, лучше вместо внутреннего вызова strcat применить функцию:
strcpy(S,S1)
При анализе текстовых строк часто надо найти в одной из строк фрагмент текста, заданный в другой строке. Этот фрагмент, например, может быть некоторым ключевым словом, символом и т.п. Эту задачу позволяет решить функция:
strstr(S1,S2)
которая ищет в строке S1 первое вхождение текста строки S2 и, если поиск прошел удачно, возвращает указатель на первый символ этого вхождения. Если же текст не был найден, возвращается нуль.
Пусть необходимо найти в строке S1 первое вхождение текста строки S2 и, если поиск прошел удачно, то заменить найденный фрагмент на текст, содержащийся в строке S3. Иначе говоря, требуется произвести контекстную замену в S1 текста S2 на текст S3. Один из возможных вариантов решения этой задачи приведен ниже:
char S1[20], S2[20], S3 [20], S[60], *St; // операторы занесения текста в S1, S2, S3
St = strstr(S1,S2);
if(St)
{
*St = 0;
St += strlen(S2);
Label1->Caption = strcat(strcat(strcpy(S,S1),S3),St);
}
else
Label1->Caption = "Текст не найден";
Помимо строк S1, S2, S3 в этом коде объявлена строка S, являющаяся буфером, в который будет помещаться текст с произведенной в нем заменой. Объявлен также указатель на строку St. Он потребуется в качестве вспомогательной переменной.
Первый выполняемый оператор кода ищет с помощью функции strstr вхождение строки S2 в строку S1 и присваивает результат поиска переменной St. Если функция strstr вернула нуль (это эквивалентно false), то печатается сообщение «Текст не найден». Если же поиск прошел успешно, то осуществляются следующие операции. Сначала в символ, на который указывает St, засылается 0 - это эквивалентно нулевому символу. Таким образом выделяется первая часть строки S1, расположенная до заменяемого текста. Затем указатель St сдвигается на длину заменяемого текста, которая определяется функцией strlen. После этой операции St начинает указывать на первый символ в строке S1 после заменяемого текста. Следующий оператор формирует в буфере S текст с заменой и отображает его в метке Label1. Формирование текста осуществляется вложенными вызовами функций strcat и strcpy. Сначала срабатывает вложенный вызов strcpy. Он копирует в S строку, на которую указывает S1. Но поскольку вместо первого символа заменяемого текста мы занесли нулевой символ, то скопирована будет только начальная часть строки S1 до этого символа. Затем срабатывает вложенный вызов strcat и к тексту, сформированному в S добавляется строка S3. Последний внешний вызов streat добавляет к сформированному тексту часть строки S1, расположенную после замененного фрагмента. Именно на эту часть строки указывает St.
Чтобы это стало понятнее, разберем пример. Пусть строка S1 содержит текст «Маша ела кашу», строка S2 содержит текст «ела», а строка S3 «съела». Значит строка S1 представляет собой массив:
'М', 'а', 'ш', 'а', ' ', 'е', 'л', 'а', ' ', 'к', 'а', 'ш', 'у', '\0'
После выполнения функции strstr указатель St будет указывать на шестой символ букву 'е'. После того как в этот символ заносится нуль, строка S1 имеет вид:
'М', 'а', 'ш', 'а', ' ', '\0 ' , 'л', 'а', ' ', 'к', 'а', 'ш', 'у', '\0'
После изменения Pt он начинает указывать на девятый символ пробел после слова «ела». После вызова strcpy в строку S копируется первая часть строки S1, завершающаяся нулевым символом:
'М', 'а', 'ш', 'а', ' ', '\0'
После вложенного вызова strcat к строке S добавляется текст строки S3:
'М', 'а', 'ш', 'а', ' ', 'с', 'ъ', 'е', 'л', 'а', '\0'
И после внешнего вызова strcat к S добавляется строка, на которую указывает St, т.е. часть строки S1, начинающаяся с пробела после «ела»:
'М', 'а' , 'ш' , 'а', ' ', 'с', 'ъ', 'е', 'л', 'а', ' ', 'к, 'а', 'ш', 'у', '\0'
В качестве последнего примера рассмотрим использование функции sprintf. Пусть в приложении имеется окно редактирования Edit1, в котором пользователь вводит фамилию сотрудника, и компонент CSpinEdit1 типа TCSpinEdit, в котором вводится год рождения. Так нужно сформировать строку вида «Сотрудник ..., ... г.р.», в которой вместо точек должны подставляться введенные данные: фамилия и год. Это можно сделать следующим кодом:
#include <stdio.h>
char S[40];
sprintf(S, "Сотрудник %s, %i г.p.", Edit1->Text, CSpinEdit1->Value);
Первый аргумент функции sprintf - формируемая строка. Второй это строка форматирования. Она указывает текст формируемой строки и содержит спецификаторы, записываемые после символа "%", которые указывают формат включения в строку аргументов, список которых расположен в вызове sprintf после строки форматирования. В данном случае первый из этих параметров текст в окне Edit1, вводимый со спецификатором %s, что означает строку, а второй параметр значение года в компоненте CSpinEdit1, вводимое со спецификатором %i, что означает целое число.
C++ Builder не ограничивается изложенным выше типичным для С++ подходом, сводящим строки к массивам символов. В нем реализованы в виде классов еще некоторые очень полезные типы. Наиболее интересные из них AnsiString, имеющий множество методов и перегруженных операций, облегчающих работу со строками, и типы списков строк TStrings и TStringList.