Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛекцииЛаб(Часть_1_Книги).doc
Скачиваний:
7
Добавлен:
03.05.2019
Размер:
1.04 Mб
Скачать

5.3. Анализ строковых функций.

Подробное описание встроенных функций для работы со строками как массивами символов с завершающим нулём можно найти в справочной литературе ( [ ], часть 2, глава 2 ).

Прототипы функций для работы со строками находятся в заголовочном файле string.h, а для работы с символами — в файле ctype.h.

В заголовке функции в качестве параметров в скобках могут использоваться следующие типы данных.

Параметр, описанный как char *str, означает указатель на строку. Если перед ним записано ключевое слово const, то это говорит о том, что данный параметр в функции не меняется. Например, из следующего прототипа функции копирования

char *strcpy (char *str1, const char * str2)

видно, что вторая строка после выполнения функции останется без изменения. Иногда, но не всегда, это помогает по одному заголовку функции понять назначение таких параметров. Для приведенной выше функции слово const “подсказывает” нам, что вторая строка копируется на место первой, а не наоборот.

Тип int ch используется чаще всего для объявления одного символа. Но так как типы int и char совместимы, то при вызове функции вместо такого параметра можно указывать переменную, объявленную с типом char, то есть один символ.

Для объявления целых чисел, которые, как правило, означают количество символов, используется тип size_t. Он определён в соответсвующих заголовочных файлах и является беззнаковым целым числом, то есть unsigned int. Например, в функции

char *strncpy (char *str1, const char * str2, size_t)

третий параметр определяет количество копируемых символов.

Приведём классификацию функций по типу возвращаемых параметров и по назначению.

1). Многие строковые функции имеют тип char *. Это означает, что они возвращают указатель на начало найденной или полученной строки или адрес найденного в строке символа. По назначению такие функции можно разделить на следующие группы.

Функции копирования:

char *strcpy(char* s1, const char* s2) — строку s2 копирует в s1;

char *strncpy(char* s1,const char* s2, size_t count) — копирует не более count символов из строки s2 в s1;

char *strdup(const char *s) — выделяет память для хранения копии строки, на которую указывает s, копирует эту строку в выделенную область и взвращает указатель на неё.

Функции соединения строк:

char *strcat(char* s1, const char* s2) — строку s2 присоединяет к строке s1;

char *strncat(char* s1, const char* s2, size_t count) — не более count символов из строки s2 присоединяет к строке s1.

Функции поиска:

char * strchr( const char* s, char c) — находит первое вхождение символа с в строку s. Возвращает указатель на найденный символ или NULL, если символ не обнаружен.

char * strrchr( const char* s, char c) — находит последнее вхождение символа с в строку s. Возвращает указатель на найденный символ или NULL, если символ не обнаружен.

char * strstr( const char* s, const char* substr) ищет в s первое вхождение подстроки substr. Возвращает указатель на первый символ найденной подстроки или NULL, если такая подстрока не найдена.

char *strpbrk( const char *s1, const char *s2) — возвращает указатель на первый символ в строке s1, совпадающий с каким-нибудь из символов строки s2. При этом нулевые сиволы в конце строк в рассмотрение не включаются.

char * strtok( const char* s1, const char* s2) — возвращает указатель на следующую лексему (часть строки) в строке s1. Символы строки s2 используются как ограничители, определяющие лексему. Как и в других функциях поиска, если лексема не найдена, возвращается NULL.

Функции преобразования строк:

char * strupr( char* s) — английские буквы нижнего регистра (“маленькие”) строки, на которую указывает s, преобразует в соответствующие буквы верхнего регистра (в “большие”). Остальные символы не меняются;

char * strlwr( char* s) — английские буквы верхнего регистра (прописные) строки, на которую указывает s, преобразует в соответствующие буквы нижнего регистра (в “маленькие”). Остальные символы не меняются.

Пример.

char *S=" F f G g{}()?,><*&^%:12 () BCD, ab";

puts(strupr(S)); // получим F F G G{}()?,><*&^%:12 () BCD, AB

puts(strlwr(S)); // f f g g{}()?,><*&^%:12 () bcd, ab

char * strrev(char *s) — “переворачивает” строку, то есть изменяет на обратную последовательность символов в строке, на которую указывает s. При этом нулевой символ конца строки остаётся на прежнем месте;

char * strset(char *s, int ch) — присваивает всем символам строки, на которую указывает s, значение символа ch и возвращает s;

char * strnset(char *s, int ch, size_t count) — присваивает первым count символам строки, на которую указывает s, значение символа ch и возвращает s;

Для всех функций типа char * важно обратить внимание на следующее. Результат некоторых, но не всех таких функций содержится в качестве возвращаемого параметра функции в скобках. Тогда такую функцию можно вызвать двумя способами. Пусть char *S1=”Borland “; char *S2=”Pascal”, *p;.

Вариант 1. Сначала вызываем такую функцию strcat(S1,S2);. Полученный результат соединения двух строк записан в скобках (S1). Эту полученную строку S1 можно использовать дальше в программе. Например, p=strrchr(S1, ‘a’); puts (p); В результате будет выведена часть строки, начинающаяся с последнего символа a соединённой строки Borland Pascal, то есть “al”.

Вариант 2. Это же можно выполнить и так: p=strrchr(strcat(S1,S2),'a'); puts (p); Результат будет такой же.

Но есть функции типа char *, которые не содержат результат в скобках в качестве параметра. К ним можно отнести функции поиска, преобразования и некоторые другие. В качестве примера рассмотрим функцию копирования char *strdup(const char *s). Она выделяет память для хранения копии строки, на которую указывает s, копирует эту строку в выделенную область и возвращает указатель на неё. Другими словами, эта функция похожа по назначению на strcpy. Но отличается вызовом, так как результата в скобках в качестве параметра нет. Поэтому её можем вызвать, используя только указанный выше второй способ:

char *S3=”Borland “; char *S4; S4=strdup(S3); puts(S4);

Заметим, что операция new для S4 не нужна. А при использовании функции strcpy, во-первых, для строки приёмника необходимо выполнить операцию new. Во-вторых, такую функцию можно вызвать двумя указанными выше способами (см. Варианты 1 и 2). Выполнить это в качестве упражнения.

2) Ряд функций возвращают беззнаковое целое число предопределённого типа size_t. К ним можно отнести, например, следующие функции:

size_t strlen(s) возвращает длину строки;

size_t strspn(char* p, char* pat) возвращает количество подряд идущих символов, которые есть в строке pat, начиная с адреса p;

size_t strcspn(char* p, char* pat) возвращает количество подряд идущих символов, которых нет в строке pat, начиная с адреса p;

Вызов таких функций выполняется как вызов функции с одним результатом, то есть функции с return (см. пример 4 и другие).

3) Есть функции, которые возвращают целое число типа int как результат сравнения двух строк. Это, например, следующие функции:

int strcmp (const char* s1, const char* s2) сравнивает две строки и возвращает 0, если они совпадают, отрицательное число, если s1<s2, и положительное число, если s1>s2;

int stricmp (const char* s1, const char* s2) сравнивает две строки, не делая различия между буквами верхнего и нижнего регистров, и возвращает 0, отрицательное или положительное число;

int strncmp (const char* s1, const char* s2, size_t count) сравнивает не более чем count символов двух строк и в зависимости от результата сравнения возвращает 0, отрицательное или положительное число;

int strnicmp (const char* s1, const char* s2) сравнивает не более чем count символов двух строк, не делая различия между буквами верхнего и нижнего регистров, и возвращает 0, отрицательное или положительное число.

Почему нельзя сравнивать строки “”обычным образом”, то есть, например, так: if (S1>S2) … ? Дело в том, что в таком случае будут сравниваться не сами строки, а адреса их начала. Как мы знаем, для указателей разрешены такие операции сравнения, поэтому синтаксической ошибки не будет, но результат выполнения будет не тот, который нам нужен.

Правильно будет, если используем, например, функцию сравнения:

if strcmp(S1, S2)>0 …

При этом сравнение строк выполняется следующим образом. Сравниваются коды каждой пары символов. Та строка будет больше, у которой код первого несовпадающего символа больше. Например, if (strcmp(“информация”,”информатика”)>0)cout<<”Yes”; else cout<<”No”; в результате выведет Yes”, так как код символа ‘ц’ больше кода символа ‘т’. При этом длина строки не учитывается. И только если общие символы одинаковы, то более длинная строка будет больше. Например, строка “математика” больше строки “математик”. При этом учитывается наличие пробелов. Если бы, например, в последнем слове в конце был пробел (“математик ”), то с ним сравнивался бы последний символ слова “математика”. И так как код пробела меньше кода символа ‘а’, то слово “математик ” с пробелом в конце меньше слова “математика”.

4) Есть “функции” (а точнее макросы) для анализа одного символа, имена которых начинаются с is, и возвращающие целое число типа int. Если символ принадлежит соответствующей группе, то получается ненулевое значение, которое интерпретируется как true. В противном случае возвращается нуль (false). Далее приведены такие наиболее часто используемые функции. Рядом записана группа символов, на принадлежность которой проверяется символ.

int isalpha (int ch) —буква алфавита верхнего или нижнего регистра;

int islower(int ch) —буква нижнего регистра (‘a’—‘z’);

int isupper(int ch) —буква верхнего регистра (‘A’ —‘Z’);

int isdigit(int ch) — десятичная цифра от 0 до 9;

int isxdigit(int ch) шестнадцатиричная цифра, принадлежащая одному из следующих отрезков: ‘A’ — ‘F’, ‘a’— ‘f’, ‘0’— ‘9’;

int isalnum (int ch) —буква алфавита верхнего или нижнего регистра, либо цифра ;

int isgraph (int ch) —печатный символ, отличный от пробела. Значения печатных символов находятся в пределах от 0x21 до 0x7E;

int isprint (int ch) —печатный символ, включая пробел (коды 0x20 — 0x7E);

int ispunct(int ch) —знак пунктуации или пробел;

int isspace (int ch) — символ пробела, возврата каретки, вертикальной или горизонтальной табуляции, перевода новой строки;

int isctrl(int ch) — управляющий символ (коды 0 — 0x1F или 0x7F);

Формальным единственным параметром всех таких функций является один символ. Поэтому при анализе строки их вызов записывается, как правило, в цикле. Рассмотрим пример: char *S=" F f G g{}()?,><*&^%:12!№() BCD, ab;fБВГДбвгж"; unsigned k=0;

for (int i=0; S [i]; i++) if (isupper(S [i])) k++; cout<<endl<<k;

В результате получим число 5 — количество английских букв верхнего регистра (“больших”, прописных) в заданной строке S.

5) Следующие две функции преобразуют символ:

int tolower(int ch) — возвращает соответствующий нижнему регистру эквивалент символа ch, если ch — это буква верхнего регистра. В противном случае символ не меняется;

int toupper (int ch) — возвращает соответствующий верхнему регистру эквивалент символа ch, если ch — это буква нижнего регистра. В противном случае символ не меняется.

Например, рассмотрим следующий фрагмент:

char *S=" F f G g{}()?,><*&^%:12!№() BCD, ab;fБВГДбвгж";

for (int i=0; S [i]; i++) S [i]=tolower(S7[i]); puts(S);

В результате в строке изменятся только “большие” английские буквы ‘F’, ’G’, ’B’, ’C’, ‘D’ на соответствующие “маленькие” ‘f’, ’g’, ’b’, ’c’, ‘d’. Эти функции похожи по своему назначению на strlwr и strupr (см. функции преобразования в подпункте 1). Отличие функций tolower и toupper в том, что они преобразуют один символ. Поэтому для преобразования строки их вызов записывается в цикле, так как входным и выходным параметром этих функций является символ А функции strlwr и strupr за один вызов преобразуют всю строку.