Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Поиск подстроки в строке




Функции работы со строками и символами

Строка представляет собой массив символов, заканчивающийся нуль-символом’\0’. В С++ есть две возможности работы со строками: функции, унаследованные из библиотеки С (заголовочный файл <string.h> или <cstring>), и библиотечный класс С++ string, предоставляющий более широкие возможности представления, обработки и контроля строк. Класс string более безопасен, чем С-строки, но и более ресурсоемок. Для его грамотного использования требуется знание основ объекто-ориентированого программирования, поэтому мы рассмотрим его позже, а сейчас ограничимся строками С.

Описание строк

Память под строки, как и под другие массивы, может выделятся как компилятором, так и непосредственно в программе(динамически). Длина динамической строки может задаватся выражением, длина не динамической строки только - константным выражением. Чаще всего используют частный случай константного выражения – именованую константу.

const int len_str=80;

char str[len_str];

при задании длины необходимо учитывать завершающий нуль-символ. Например,в приведенной выше строке можно хранить не 80 символов, а только 79. При описании можно инициализировать строку строковой константной(нуль-символ, следующий за последним символом, формируется автоматически):

char a[100]=”Пример стороки”;

Если сторка инициализируется, её размерность можно опускать – компилятор сам выделит память, достаточную для размещения всех символов строки и завершающего символа:

char a[]=”Пример стороки”;

Для размешения строки в динамической памяти надо описать указатель на char, а затем выделить память с помощью new или malloc:

char *p = new char[m];

char *q = (char *)malloc(m*sizeof(char));

В этом случае длина строки может быть переменной и задаватся на этапе выполнения прогараммы. Динамические строки, как и другие динамические массивы, нельзя инициализировать при создании. Следующий оператор создает не строковую переменную, а указатель на строковую константу, изменить которую невозможно:

char *str =”Пример константной строки”;

Присваивание вида str[2]='w' для такого указателя, хотя и компилируются, могут вызывать ошибки времени выполнения.

Для ввода вывода используются известные функции scanf и printf, задав спецификацию формата %s:

char s[10];

scanf(“%s”, s); printf(“%s”,s);

Имя строки, как и имя любого массива, является указателем на его начало, поэтому операция взятия адреса(&) опущена. Ввод будет выполнятся до первого пробельного символа(пробела, знака табуляции или символа перевода строки): если ввести несколько слов, воспринимается только первое. Чтобы ввести строку, состоящую из нескольких слов, используется спецификация %c(символы) с указанием максимального количества вводимых символов, например scanf(“%10c”,s).(ожидает все 10 символов)

Количество символов может быть только целой константой. При выводе можно задать перед спецификацией %s количество позиций отводимых под строку: printf(“%15s”,s). строка при этом выравнивается по правому краю отведенного поля. Если заданного количества недостаточно для размешения строки, оно игнорируется, и строка выводится целиком.

Библиотека содержит функции gets и puts, специально предназначенные для ввода-вывода строк.

gets(s); puts(s);

Функция gets(s) читает символы с клавиатуры до появления символа новой строки и помещает их в строку s(сам символ новой строки в строку не включается, вместо него в строку заносится нуль символ). Функция возвращает указатель на строку s, а в случае возникновения ошибки или конца файла – NULL.

Функция put(s) выводит строку s на стандартное устройство вывода, заменяя значащий ноль символом новой строки. Возвращеат неотрицательное число в случае успеха или EOF при ошибке.

Функциями семейства printf удобнее пользоватся в том случае, если в одном операторе требуется ввести или вывести данные различных типов. Если же работа выполняется только со строками, проще применять специальные функции для ввода вывод строк gets и puts.

Cледующая программа присваивает буквы от А до Z переменной alphabet, используя цикл for. Затем программа добавляет символ NULL в эту переменную и выводит ее с помощью cout.

char alphabet [27]; // 26 буквы плюс NULL char letter;

int index=0;

for (char letter = 'A'; letter <= 'Z';

letter++, index++) alphabet[index] = letter;

alphabet[index] = '\0';

printf("Bukva %s", alphabet);

При рассмотрении программ на C++ вы можете встретить символы, заключенные в одинарные кавычки (например, 'А') и символы, заключенные в двойные кавычки ("А"). Символ внутри одинарных кавычек представляет собой символьную константу. Компилятор C++ выделяет только один байт памяти для хранения символьной константы. Однако символ в двойных кавычках представляет собой строковую константу — указанный символ и символ NULL (добавляемый компилятором). Таким образом, компилятор будет выделять два байта для символьной строки.

Передача символьной строки в функцию подобна передаче любого массива в качестве параметра. Внутри прототипа функции вам нужно просто указать тип массива (char) и левую и правую скобки массива. Вам не надо указывать размер строки. Например, следующая программа использует функцию len_ string для нахождения длины символьной строки:

int len_string(char string[])

{ int i;

for(i=0;string[i]!=0;i++);

return i;

}

void main(void)

{

cout<<len_string("Привет, C++!");

cout<<len_string("Учусь программировать на C++");

}

Как видите, функция len_string трактует параметр символьной строки как массив:

int len_string(char string[])

Так как символ NULL указывает конец строки, функция не требует параметр, который задает количество элементов в массиве. Вместо этого функция может определить последний элемент, просто найдя в массиве символ NULL.

 

Операции со строками.

Для строк не определены операции присваивания, сравнения, сцепления поскольку они не явлаются основными типами данных.Эти операции делаются посимвольно «вручную» или с помощью функции библиотеки.

Библиотека С содержит функции копирования строк (strcpy, strncpy), сравнения (strcmp, strncmp), объединения строк (strcat, strncat), поиска подстроки (strstr), поиска вхождения символа (strchr, strrchr, strpbrk), определения длины строки (strlen) и др.

Присваивание строк

Первый и самый очевидный способ присваивания строк – присваивание отдельных символов. Например,

str1[0]=’H’;str1[1]=’e’;str1[2]=’l’;str1[3]=’l’;str1[4]=’o’;str1[5]=’\0’;

Однако, это совершенно неудобно. Не зная о правильных способах, начинающие программисты часто «выдумывают» свои способы присваивания строк, конечно, неправильные. Приведу несколько примеров:

char str1[10], str2[10];str1="Hello";str2=str1;//Одна и та же ошибка в обоих операторах =. //Имя массива нельзя использовать в левой части оператора присваивания.

Эта ошибка относительно безопасна, так как приводит к сбою на этапе компиляции. Есть и гораздо более опасная ошибка.

char str1[10]= "Hello";char* str2;str2=str1;str2[1]='u';

Этот код откомпилируется, но, возможно, содержит «идеологическую» ошибку. Неправильно полагать, что в str2 теперь содержится копия str1. На самом деле этот указатель указывает не на копию, а на ту же самую строку. При любом изменении содержимого str2 изменяется str1. Однако, если именно это и требуется, то все в порядке.

Еще один вариант присваивания указателей – присваивание их строковым литералам. Как вы помните, тип строкового литерала – const char*, а значит такой код работает:

const char* str;str="Hello";

Опять же следует помнить, что str указывает на строковый литерал, а не на его копию. Но, к сожалению, такой код тоже сработает:

char* str; // Нет conststr="Hello";

Здесь мы имеем дело с наследством C, в котором отсутствовал const. Поэтому стандарт С++ разрешает такое присваивание. Что может иметь неприятные последствия:

char* str; // Нет conststr="Hello";str[1]=’u’;

Результат работы такой программы непредсказуем. Компилятор может разместить константы в памяти только для чтения, и попытка их изменить приведет к сбою. Поэтому всегда объявляйте указатели, в которые вы собираетесь записывать адреса строковых литералов как const char*. В этом случае компилятор не позволит модифицировать данные и диагностирует ошибку, что поможет вам исправить логику программы.

const char* str; // const естьstr="Hello";str[1]=’u’; //error: l-value specifies const object

Вопросы неправильного и рискованного присваивания строк мы рассмотрели. Пришла пора обсудить правильное присваивание или копирование строк.

 

Для копирования строк существуют несколько библиотечных функций, наиболее общеупотребительной из которых является функция

char* strcpy(char* dest, const char* src)

Функция посимвольно копирует содержимое строки, на которую указывает src в строку, на которую указывает dest и возвращает dest. Так как массив может быть преобразован в указатель, такой вызов функции абсолютно легален:

char str1[10], str2[10]; strcpy(str1, "Hello"); strcpy(str2, str1);

При использовании этой функции следует соблюдать осторожность. Опасность заключается в том, что даже если исходная строка окажется больше, чем память, выделенная для второй строки (dest) (программистом через malloc или компилятором при использовании массивов), функция strcpy никак про это узнать не сможет и продолжит копирование в невыделенную память. Разумеется, последствия будут катастрофическими.

Снизить риск такого развития событий способна функция

char* strncpy(char* dest, const char* src, size_t count)

Последний параметр – максимальное количество копируемых символов. Таким образом, передавая туда размер приемника, вы гарантируете, что функция никогда не выйдет за пределы выделенной памяти. Однако помните, что если исходная строка будет скопирована не полностью, нуль-символ не появится в результирующей строке. Его придется записать самостоятельно.

Длина строки

Для вычисления длины строки используется функция

size_t strlen(const char *string);

Функция возвращает длину строки, не включая нуль-символ. Как всегда, следите за тем, чтобы в выделенной под string памяти все же нашелся такой символ. В противном случае функция выйдет за пределы выделенной памяти и все будет плохо. Напомню, что для определения длины строки функции придется последовательно обратиться ко всем ее символам до нуль-символа, а значит, потенциально эта операция довольно дорогая. Поэтому, не следует использовать эту функцию в циклах, то есть вместо

for (i=0;i<strlen(str);i++) { // работа со строкой, не изменяющая ее длину}

больше подойдет примерно такой код:

char len;len=strlen(str);for (i=0;i<len;i++) { // работа со строкой, не изменяющая ее длину}

 

В заголовочных файлах <stdlib.h> и <cstdlib> содержатся полезные функции преобразования строк в числа:

Доступно целое семейство функций atof, atoi, atol и itoa, ltoa. Все они очень похоже между собой. Функции из первой группы преобразуют строку в число (float, int или long) в зависимости от окончания. Функции из второй группы выполняют обратное преобразование. Функции из второй группы не входят в стандарт С, однако они весьма удобны и доступны на некоторых платформах.

Прототипы функций из первой группы:

double atof(const char* string); int atoi(const char* string); long atol(const char* string);

 

Признаком конца числа служит первый символ, который не может быть интерпретирован как принадлежащий числу. если преобразование не удалось возвращается 0.

 

char a[]=”10) Рост – 162, вес – 63.5кг”;

int num = atoi(a);

long height = atol(&a[11]);

double weigth = atof(&a[25]);

Пробелы и табуляции в начале строки пропускаются. Преобразование прекращается при встрече недопустимого символа или конца строки. Если строку нельзя преобразовать в число, возвращается 0.

Вторая группа:

char* itoa(int value, char* string, int radix); char* ltoa(long value, char* string, int radix);

Функции из второй группы могут создавать строковое представление чисел в любой системе (по любому основанию) от 2 до 36. Основание передается в третьем параметре. Чтобы получить строковое представление числа в десятичной системе, передайте 10. Функции возвращают указатель на строку.

ПРИМЕЧАНИЕ При использовании этих функций не забывайте выделять память, достаточную для предоставления строкового предоставления числа. Например, максимальная длина десятичного строкового представления четырехбайтного беззнакового целого числа - 11 байт, включая нуль-символ ("4294967295").

Пример:

char str1[5]; char str2[5]; char str3[5]; itoa(12, str1, 10); //str1=”12” itoa(12, str1, 16); //str1=”C” itoa(12, str1, 2); //str1=”1100”

 

Для хранения отдельных символов используются переменные типа char. Их ввод вывод может выполнятс функциями

getchar() и putchar()

char c;

c=getchar(); putchar(c);

Для работы с символами в стандартной библиотеке (заголовочные файлы <ctype.h> и <cctype>) есть следующие функции:

Таблица 4.1.
Имя Проверка на принадлежность символа множеству
isalnum букв и цифр (A-Z, a-z, 0-9)
isalfa букв (A-Z, a-z)
iscntrl управляющих символов (с кодами 0..31 и 127)
isdigit цифр (0-9)
isgraph Печатаемых символов, кроме пробела (isalfa | isdigit | ispunct)
islower букв нижнего регистра (a-z)
isprint Печатаемых символов
ispunct знаков пунктуации
isspace символов-разделитетей
isupper букв верхнего регистра (A-Z)
isxdigit шестнадцатеричных цифр (A-F, a-f, 0-9)

 

Поиск подстроки в строке

Char *strstr(char *s1, char *s2); Поиск первого вхождения подстроки s2 в строку s1. Возвращает указатель на элемент из s1, с которого начинается s2.

Выполняет поиск подстроки продстроки s2 в строке s1. Обе строки должны завершаться нуль-символами. В случае успешного поиска функция возвращает указатель на найденную подстроку, в случае неудачи – NULL(пустой указатель). Если искомоя подстрока пуста, функция возвращает указатель на начало строки s1.

const int len =80;

char word[len],line[len];

printf(“Введите предложение:”);

gets(line);

printf(“Введите слово для поиска:”);

gets(word);

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...