Функции работы со строками и символами 1
Литература • Выжол Ю. А. Лек 08. Операции со строками 2
МАССИВЫ СИМВОЛОВ В C++ Строка представляет собой массив символов, заканчивающийся нуль-символом. В С++ есть две возможности работы со строками: функции, унаследованные из библиотеки С (заголовочный файл <string. h> или <cstring>), и библиотечный класс C++ string, предоставляющий более широкие возможности представления, обработки и контроля строк. 3
МАССИВЫ СИМВОЛОВ В C++ При объявлении строкового массива необходимо принимать во внимание наличие терминатора в конце строки, отводя тем самым под строку на один байт больше: char buffer [10] ; // объявление строки размером 10 символов, //включая терминатор. // Реальный размер строки: 9 символов + терминатор. Строковый массив может при объявлении инициализироваться начальным значением. При этом компилятор автоматически вычисляет размер будущей строки и добавляет в конец нуль-терминатор: char Wednesday [ ] = ”Среда”; // объявление и инициализация строки char Wednesday [ ] = {’С’, ’р’, ’е’, ’д’, ’а’, ’ ’} ; // что равносильно 4
МАССИВЫ СИМВОЛОВ В C++ В качестве оператора ввода при работе со строками вместо оператора записи в поток >> лучше использовать функцию getline ( ), так как потоковый оператор ввода игнорирует вводимые пробелы, а кроме того, может продолжить ввод элементов за пределами массива, если под строку отводится меньше места, чем вводится символов. Синтаксис функции getline ( ) имеет вид: getline ( char* pch , int n. Count , char delim = ’n’ ) ; Функция getline ( ) принимает два обязательных параметра: первый аргумент pch указывает на строку, в которую осуществляется ввод, а второй параметр n. Count – число символов, подлежащих вводу. Третий необязательный параметр delim – символ, который будет преобразован в нуль-терминатор. По умолчанию 5 это символ конца строки ’n’.
МАССИВЫ СИМВОЛОВ В C++ Рассмотрим пример объявления символьных строк и использования функции ввода getline ( ). char S [ 6 ] ; // объявляет и инициализирует строку длиной в 5 символов cout << ”Input string: ” ; // выводит на экран приглашение cin. getline ( S , 6 , ’. ’ ) ; // ввод строки длиной не более 5 символов, завершается точкой cout <<”You string: ”<< S <<’n’ ; // выводит строку на экран 6
Основные функции работы с символьными массивами • strlen ( ) возвращает длину строки в байтах, не учитывая нуль-терминатор • strcpy ( ) копирует строку2 в строку1 • strncpy ( ) копирует заданное число символов строки 2 в строку1 • strdup ( ) распределяет память и делает копию строки • strcat ( ) присоединяет строку2 в конец строки 1 • strncat ( ) присоединяет заданное число символов строки 2 в конец строки 1 • strcmp ( ) сравнивает строку1 со строкой 2, различая прописные и строчные буквы • stricmp ( ) сравнивает строку1 со строкой 2, не различая прописные и строчные буквы 7
Основные функции работы с символьными массивами • strncmp ( ) сравнивает заданное число символов двух строк, различая прописные и строчные буквы • strnicmp ( ) сравнивает заданное число символов двух строк, не различая прописные и строчные буквы • strlwr ( ) преобразует все символы строки в строчные буквы • strupr ( ) преобразует все буквы строки в прописные буквы • Char. To. Oem ( ) производит преобразование кодов символов строки 1 таким образом, что строка строку2 правильно отображает символы кириллицы в консольном приложении • strrev ( ) реверс строки • strchr ( ) возвращает позицию первого вхождения символа в строку • strrchr ( ) отыскивает последнее вхождение символа в строке • strspn ( ) возвращает позицию в строке первого символа, который не принадлежит заданному набору символов 8
Основные функции работы с символьными массивами • strnset ( ) помещает заданный символ в заданное число позиций строки • strset ( ) помещает символ во все позиции строки • isalnum(c) возвращает истину, если символ c является буквой или цифрой • isalpha(c) возвращает истину, если символ c является буквой • isascii(с) возвращает истину, если код символа с <= 127 • iscntrl(с) возвращает истину, если с – управляющий символ • isdigit(c) возвращает истину, если с – символ десятичной цифры • isgraph(с) возвращает истину, если с – печатаемый символ (код от 33 до 126) 9
ОПРЕДЕЛЕНИЕ ДЛИНЫ СТРОК Очень часто при работе со строками необходимо знать, сколько символов содержит строка. Для выяснения информации о длине строки в заголовочном файле string. h описана функция strlen ( ). Синтаксис этой функции имеет вид: size_t strlen ( const char* string ) ; Данная функция в качестве единственного параметра принимает указатель на начало строки string, вычисляет количество символов строки и возвращает полученное беззнаковое целое число типа size_t. Функция strlen ( ) возвращает значение на единицу меньше, чем отводится под массив по причине резервирования места для символа ’ ’. Следующий фрагмент демонстрирует использование функции strlen ( ): char S [ ] = ” 0123456789” ; // объявляет и инициализирует строку длиной 10 символов cout << ”Lenght=” << strlen ( S ) << ’n’ ; // выводит на экран Length = 10 cout << ”Size =” << sizeof ( S ) << ’n’ ; // выводит на экран Size = 11 10
ОПРЕДЕЛЕНИЕ ДЛИНЫ СТРОК Часто функция sizeof используется при вводе строк в качестве второго параметра конструкции cin. getline ( ), что делает код более универсальным, так как не требуется явного указания числа вводимых символов. Если теперь потребуется изменить размер символьного массива, достаточно модифицировать лишь одно число при объявлении строки символов: char S [20] ; // объявляет строку длиной 19 символов cin. getline ( S , sizeof ( S ) ) ; // ввод строки длиной не более 19 символов с клавиатуры 11
КОПИРОВАНИЕ СТРОК Значения строк нельзя копировать с помощью оператора присваивания. Следующий пример демонстрирует результат попытки использования оператора присваивания для копирования строк. char S [21] =”First”, C [21] = ”Second”; // объявляет и инициализирует две строки S = C ; // попытка скопировать строку – ОШИБКА!!! strcpy ( S , ”String” ) ; // копирует строку "String" в строку S cout<<S<<’t’<<C<<’n’ ; // выводит на экран строки S и C Для понимания результатов работы приведённого фрагмента кода необходимо иметь в виду, что идентификаторы S и C являются указателями. Поэтому после выполнения оператора S = C идентификаторы S и C указывают на одну и ту же область памяти, а адрес строки ”First” теряется. Если мы копируем в строку S новое значение, то меняется и значение строки C. Последний оператор выведет на экран: String Значения строк могут копироваться из одной в другую. Для этой цели используют ряд стандартных функций, описываемых ниже. 12
Копирование строки. Функция strcpy ( ) имеет прототип: char* strcpy ( char* str 1 , const char* str 2 ) ; и выполняет побайтное копирование символов из строки, на которую указывает str 2, в строку по указателю str 1. Копирование прекращается только в случае достижения нуль-терминатора строки str 2, поэтому перед копированием необходимо удостовериться, что длина str 2 меньше или равна длине str 1. В противном случае возможно возникновение ошибок, связанных с наложением данных. Например, следующий фрагмент копирует в строку S значение строки "String copy": char S [21] ; // объявляет строку длиной 20 символов strcpy ( S , ”String copy” ) ; // копирование строки "String copy" в строку S cout<<S<<’n’ ; // вывод на экран строки S 13
Копирование строки. Функция strcpy Можно производить копирование не всей строки, а лишь отдельного ее фрагмента (до конца строки). При этом второй параметр является указателем на некоторый элемент строкового массива. Необходимо иметь в виду, что идентификатор строки фактически является указателем на начало строки. Например, следующий фрагмент скопирует в str 2 окончание строки str 1: char S 1 [21] = ”String copy” ; // объявляет и инициализирует строку длиной 20 символов char S 2 [21] ; // объявляет строку длиной 20 символов char* p. S = S 1 ; // объявляет указатель на строку и // инициализирует его адресом начала строки S 1 cout << p. S << ’n’ ; // выводит на экран строку "String copy" p. S += 7 ; // увеличивает адрес p. S на 7 байт cout << p. S << ’n’ ; // выводит на экран строку "copy" strcpy ( S 2 , p. S ) ; // копирует строку "copy" в строку S 2 14 cout << S 2 << ’n’; // выводит на экран строку "copy"
Копирование части строки. Функция strncpy ( ) отличается от strcpy ( ) тем, что в ее параметрах добавляется еще один аргумент, указывающий количество символов, не больше которого будет скопировано. Ее синтаксис имеет вид: char* stmcpy ( char* strl , const char* str 2 , size_t num ) ; Если длина str 1 меньше длины str 2, происходит урезание символов: char s. Long [ ] = ” 0123456789” ; // объявляет и инициализирует строку длиной 10 символов char s. Short [ ] = ”abcdef” ; // объявляет и инициализирует строку длиной 6 символов stmcpy ( s. Short , s. Long, 4) ; // копирует строку "0123" в начало строки s. Short cout << s. Short << ’n’ ; // выводит на экран строку "0123 ef" В приведённом фрагменте из строки s. Long в строку s. Short скопировано четыре первых символа с затиранием исходного значение начала короткой строки. 15
Копирование строки с выделением памяти. Функция strdup ( ) в качестве параметра получает указатель на строкуисточник, осуществляет распределение памяти, копирует в отведенную область строку и возвращает указатель на начало полученной строки-копии. Синтаксис функции следующий: char* strdup ( const char* source ) ; В следующем примере производится копирование строки, на которую указывает указатель p. S 1, в строку, на которую указывает указатель p. S 2: char* p. S ; // объявляет указатель на строку p. S = strdup (”File not found” ) ; // выделяет память для строки длиной 14 символов и // инициализирует указатель p. S адресом этой строки cout << p. S << ’n’ ; // выводит на экран строку p. S: "File not found" cout << strlen ( p. S ) << ’n’ ; // выводит на экран длину строки p. S: "14" 16
КОНКАТЕНАЦИЯ СТРОК • Конкатенация (или присоединение) строк довольно часто используется для образования новой строки символов. • Для этой операции стандартная библиотека предлагает функции strcat ( ) и strncat ( ). 17
Присоединение строки. Функция strсat ( ) имеет синтаксис: char* strcat ( char* str 1 , const char* str 2 ) ; В результате работы функции содержимое строки, на которую указывает str 2, присоединяется к содержимому строки, на которую ссылается str 1. Возвращаемый функцией указатель str 1 указывает на результирующую строку. При этом размер строкового массива str 1 должна быть достаточным для хранения объединенной строки. В следующем примере строка S инициализируется с помощью функции копирования strcpy ( ) и дополняется подстрокой, используя функцию strcat ( ): char S [26] ; // объявляет строкe длиной 25 символов strcpy ( S , ”Press any key ”) ; // инициализирует строку strcat ( S , ”to continue”) ; // добавляет в конец строки “to continue” cout << S << ’n’ ; // выводит на экран строку “Press any key to continue” 18
Присоединение части строки. Функция strncat ( ) также осуществляет конкатенацию строк, однако, присоединяет лишь указанное в третьем параметре количество символов (беззнаковое целое). Функция strnсat ( ) имеет синтаксис: char* strncat ( char* str 1 , const char* str 2 , size_t num) ; Функция возвращает указатель на начало сформированной строки str 1. При этом размер строкового массива str 1 должна быть достаточным для хранения объединенной строки. Следующий пример производит конкатенацию строки str 1 с двумя первыми символами подстроки str 2: char S 1 [31]= ”Press any key ” ; // объявляет и инициализирует char S 2 [31]= ”to continue” ; // две строки длиной 30 символов strncat ( S 1 , S 2 , 2 ) ; // добавляет два первых символа строки S 2 в конец строки S 1 cout << S 1 << ’n’ ; // выводит на экран строку “Press any key to” 19
СРАВНЕНИЕ СТРОК Библиотека функций string. h предлагает к использованию готовые функции, выполняющие сравнение строк. Из двух строк меньше та, у которой меньше код первого несовпадающего символа. Ниже приводятся функции, выполняющие посимвольное сравнение двух строк. Функция strcmp ( ) производит сравнение строк, различая прописные и строчные буквы и имеет синтаксис: int strcmp ( const char* S 1 , const char* S 2 ) ; В качестве параметров функция получает указатели на строки, которые сравниваются. После сравнения строк S 1 и S 2 данная функция возвращает в результате одно из следующих значений: – если строка S 1 меньше, чем S 2; <0 – если строки эквивалентны; =0 – если строка S 1 больше, чем S 2. >0 20
СРАВНЕНИЕ СТРОК Следующий пример иллюстрирует работу функции strcmp ( ): char S 1 [ ] = ”Иванов” ; // объявляет и инициализирует char S 2 [ ] = ”Иванцов” ; int i = strcmp ( S 1 , S 2 ) ; // объявляет переменную типа int и инициализирует её // результатом сравнения двух строк cout << ”i = ” << i << ’n’ ; // выводит на экран значение переменной cout << S 1 << ’t’ ; // выводит на экран Иванов cout<<( i>0 ? ’>’ : ( i<0 ? ’<’ : ’=’)) ; // выводит на экран символ ‘<’ , ’>’ или ‘=’ cout << ’t’ << S 2 << ’n’ ; // выводит на экран Иванцов В результате переменной i будет присвоено отрицательное значение, так как строка S 1 меньше, чем строка S 2. Первый несовпадающий символ – четвёртый, а код символа ’о’ меньше кода символа ’ц’. 21
СРАВНЕНИЕ СТРОК Библиотека string. h также содержит функции, которые сравнивают две строки, не различая регистра символов. Прототипы этих функций имеют вид: int stricmp ( const char *S 1 , const char *S 2 ) ; int strcmpi ( const char *S 1 , const char *S 2 ) ; int strncmp ( const char *S 1 , const char* S 2 , size_t n); Последняя функция сравнивает n первых символов двух строк. 22
ПРЕОБРАЗОВАНИЕ СТРОК • Элементы символьных строк могут быть преобразованы из одного регистра в другой. • Для этого используются стандартные функции _strlwr и _strupr. • Следует отметить, что в некоторых версиях компиляторов имена данных функций могут следовать без ведущего символа подчеркивания. 23
Функции strlwr, _strlwr • Функция strlwr принимает в качестве параметра указатель на строку символов, преобразует эту строку к нижнему регистру (строчные символы) и возвращает указатель на полученную строку. • Данная функция имеет следующий прототип: char* strlwr(char* str) ; • Следующий фрагмент показывает применение функции strlwr: char S [ ] = "Error" ; // объявление и инициализация строки strlwr ( S ) ; // преобразование строки в нижний регистр cout << S << 'n' ; // вывод на экран "error" 24
Функции strupr, _strupr • Функция strupr объявлена следующим образом: char* strupr ( char* str ) ; • Данная функция преобразует строку символов, на которую указывает str, в прописные буквы (к верхнему регистру). • В результате работы функции возвращается указатель на полученную строку. • Приведенные выше функции преобразования строк, работая с указателями, преобразуют исходную строку, которая не всегда может быть восстановлена, поэтому, если в дальнейшем коде программы потребуется воспользоваться оригиналом символьной строки, перед использованием функций strlwr и strupr необходимо сделать копию их аргументов. 25
Функции Char. To. Oem • В консольном приложении строки, содержащие символы кириллицы некорректно отображаются в окне приложения. • Для решения задачи соответствующего преобразования кодов символов в заголовочном файле windows. h объявлена функция Char. To. Oem, синтаксис которой имеет следующий вид: int Char. To. Oem (char* const str 1 , const char* str 2 ) ; 26
Функции Char. To. Oem • В консольном приложении строки, содержащие символы кириллицы некорректно отображаются в окне приложения. • Для решения задачи соответствующего преобразования кодов символов в заголовочном файле windows. h объявлена функция Char. To. Oem, синтаксис которой имеет следующий вид: int Char. To. Oem (char* const str 1 , const char* str 2 ) ; • Функция производит преобразование кодов символов строки str 1 таким образом, что строка символов str 2 правильно отображает символы кириллицы. • При этом строка str 1 не изменяется, а размер строкового массива str 2 должна быть достаточным для хранения преобразованной строки. 27
Функции Char. To. Oem #include <iostream. h> #include <windows. h> void main () { char S 1 [ ] = "Кириллица" ; // объявление и инициализация строки char S 2 [80] ; // объявление строки длиной 25 символов Char. To. Oem ( S 1 , S 2 ) ; // преобразование кодов символов кириллицы сout << S 1 << 'n' ; // вывод на экран "шЁшыыш. Ур" cout << S 2 << 'n' ; // вывод на экран "Кириллица" } 28
ОБРАЩЕНИЕ СТРОК • Функция обращения строки strrev меняет порядок следования символов на обратный (реверс строки). • Данная функция имеет прототип: char* strrev ( char* str ) • Следующий пример демонстрирует работу функции strrev. char S [ ] = "Hello" ; // объявление и инициализация строки cout << S << 'n' ; // вывод на экран "Hello" strrev ( S ) ; // реверс строки cout << S << 'n' ; // вывод на экран "olle. H" Эта функция также преобразует строку-оригинал. 29
ФУНКЦИИ ПРОВЕРКИ ДИАПАЗОНА • На практике довольно широко используются функции проверки принадлежности символов какому-либо диапазону, такие как isalnum, isalpha, isascii, isdigit и т. д. , объявленные в заголовочном файле ctype. h. • Синтаксис этих функций имеет вид: int isrange ( int c ) ; • Если параметр принадлежит диапазону, то функция возвращает число, большее нуля, в противном случае – ноль. • Ниже рассматривается пример использования этого вида функций. 30
ФУНКЦИИ ПРОВЕРКИ ДИАПАЗОНА #include <ctype. h> #include <iostream. h> void main () { char Age [4] ; // объявление строки из трёх символов, в которой хранится возраст char S [81] ; // объявление строки сообщений из восьмидесяти символов unsigned int i ; // объявление целочисленной переменной без знака номер символа for ( ; ; ) // бесконечный цикл { begin: // объявление метки – начало цикла Char. To. Oem ( "Ведите свой возраст, пожалуйста " , S ) ; cout << S ; // вывод приглашения cin. getline ( Age , 4 ) ; // ввод возраста 31
ФУНКЦИИ ПРОВЕРКИ ДИАПАЗОНА for ( i=0 ; i<strlen ( Age ) ; i++) // для всех символов строки Age { if ( isalpha ( Age [ i ] ) ) // если i–й символ является буквой { Char. To. Oem ( "ntt Вы ввели букву, попытайтесь снова nn" , S ) ; сout << S ; goto begin ; // вывод сообщения и переход в начало цикла } if ( iscntrl ( Age [ i ] ) ) // если i–й символ является управляющим { Char. To. Oem ( "ntt Вы ввели управляющий символ, попытайтесь снова nn" , S) ; cout<<S ; goto begin ; // вывод сообщения и переход в начало цикла } 32
ФУНКЦИИ ПРОВЕРКИ ДИАПАЗОНА if ( ispunct ( Age [ i ] ) ) // если i–й символ является символом пунктуации { Char. To. Oem ( "ntt Вы ввели символ пунктуации, попытайтесь снова nn" , S ) ; cout<<S ; goto begin; // вывод сообщения и переход в начало цикла } if ( ! isdigit ( Age [ i ] ) ) // если i–й символ не является цифрой goto begin ; // переход в начало цикла } Char. To. Oem ( "ntt Ваш возраст: " , S ) ; сout << S << Age << "nn" ; // вывод возраста return 0 ; // выход из функции } } 33
ПОИСК СИМВОЛОВ • Одна из часто встречаемых задач при работе со строками – поиск отдельного символа или даже группы символов. • Библиотека string. h предлагает широкий набор стандартных функций. • Функция strchr • Функция нахождения символа в строке strchr имеет следующий прототип: char* strchr ( const char* string , int c ) • Данная функция производит поиск символа с в строке string и в случае успешного поиска возвращает указатель на место первого вхождения символа в строку. • Если указанный символ не найден, функция возвращает NULL. • Поиск символа осуществляется с начала строки. • Ниже рассматривается фрагмент, осуществляющий поиск заданного символа в строке. 34
Функция strchr char S [81] ; // объявление строки из восьмидесяти символов char* p. S ; // объявление указателя на строку Char. To. Oem ( "Назвался U груздем, U пеняй U на U себя" , S ) ; // инициализация строки cout << S << 'n' ; // вывод на экран исходной строки p. S = strchr ( S , 'U' ) ; // возвращает указатель на первый пробел while ( p. S ) // до тех пор, пока указатель p. S не равен NULL { p. S++ ; // увеличение указателя на единицу cout << p. S << 'n' ; // вывод на экран символов от найденного пробела до конца строки p. S = strchr ( p. S , ' ' ) ; // поиск следующего пробела } 35
Функция strspn проводит сравнение символов одной строки с символами другой и возвращает позицию (начиная с нуля), в которой строки перестают совпадать. Данная функция имеет следующий прототип: size_t strspn ( const char* string , const char* group) Функция проверяет каждый символ строки string на соответствие каждому из символов строки group. В результате работы функции возвращается число совпавших символов. Следующий пример демонстрирует использование данной функции: char S 1 [ ] = "Загрузка параметров БД" ; char S 2 [ ] = "Загрузка параметррррр" ; cout << strspn ( S 1 , S 2 ) ; На экран будет выведено число 17, так как символы строки S 1 и строки S 2 совпадают вплоть до 17 -й позиции. Приведенная функция различает регистр символов. 36
ПОИСК ПОДСТРОК При необходимости поиска в одной строке последовательности символов, заданной в другом символьном массиве (подстроке, лексеме), стандартная библиотека string. h предлагает воспользоваться одной из следующих функций. Функция strstr описана следующим образом: char* strstr ( const char* str , const char* substr) Данная функция осуществляет сканирование строки str и находит место первого вхождения подстроки substr в строку str. В случае успешного поиска функция strstr возвращает указатель на первый символ строки str, начиная с которого следует точное совпадение части str обязательно со всей лексемой substr. 37 Если подстрока substr не найдена в str, возвращается NULL.
ПОИСК ПОДСТРОК char S 1 [81] ; // объявление строки Char. To. Oem ( "Производится поиск элемента" , S ) ; // инициализация строки char S 2 [81] ; // объявление строки Char. To. Oem ( "поиск" , S ) ; // инициализация строки char* p. S ; // объявление указателя на строку p. S = strstr ( S 1 , S 2 ) ; // инициализация указателя на строку cout << p. S << 'n' ; // вывод на экран "поиск элемента" 38
Функция strtok имеет синтаксис: char* strtok ( char* str , const char* delim) Эта функция выполняет поиск в строке str подстроки, обрамленной с обеих сторон любым символомразделителем из строки delim. В случае успешного поиска данная функция обрезает строку str, помещая символ '