Сравнение строк си. Функции обработки строк в Cи

Объявление строк

Строка в языке Си представляет собой одномерный массив символов, последним элементом которой является символ конца строки – нуль (строка, завершающаяся нулем, то есть NULL terminated string).

Объявление переменной типа строка в языке Си возможно тремя способами, два из которых инициализируют строку во время объявления.

Первый способ:

Объявления массива символов (не забудьте добавить место для завершающего нуля):

Char s;

Второй способ:

Присвоить строковой переменной начальное значение (при этом длину строки компилятор может вычислить сам):

Char s = "Пример инициализации строки";

Справа от знака присваивания записана строковая константа. В конце строки автоматически добавляется ноль (‘\0’). Константы символьных строк помещаются в класс статической памяти.

Третий способ:

Неявное указание, что используется массив. В левой части от знака присваивания указывается указатель на символ:

Char *s="Второй вариант инициализации";

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

Char *s;

Ввод строки со стандартного устройства ввода (клавиатуры)

Для работы со строками есть набор функций. Для ввода со стандартного устройства ввода (клавиатуры) чаще всего используются библиотечные функциями из модуля стандартного ввода-вывода: scanf и gets .

Для ввода строки с помощью функции scanf , использует формат «%s » , причем обратите внимание на то, что перед идентификатором строки не используется знак адреса «& » , так как одномерный массив уже представлен указателем на его начало:

Scanf("%s", s);

Функция gets() считывает символы до тех пор, пока не достигнет символа перехода на новую строку. Функция принимает все символы вплоть до символа перевода строки, но не включает его. К концу строки добавляется завершающий ноль (‘\0’). Функция gets() помещает считанную с клавиатуры последовательность символов в параметр типа строка и возвращает указатель на эту строку (если операция завершилась успешно), или NULL (в случае ошибки). В приведенном ниже примере при успешном завершении операции, на экран будет выведено две одинаковые строки:

#include int main() { char s; char *p; p=gets(s); printf(" \n Введена строка %s. ",s); if (p) printf(" \n Введена строка %s. ",p); return 0; }

Попутно заметим, что функция gets часто используется для ввода лю-бых данных с клавиатуры в виде строки с целью дальнейшего преобразования функцией sscanf к нужному формату или для предварительного анализа вводимых данных, например:

#include #include #include int main() { char s; int x, err; do { printf(" \n Введите целое число -> "); gets(s); err=sscanf(s, "%d",&x); if (err!=1) printf(" \n Ошибка ввода. "); } while (err!=1); printf("\n Введено целое число -> %d", x); return 0; }

Вывод строк на стандартное устройство вывода (экран монитора)

Для вывода строк на стандартное устройство вывода (экран монитора) можно использовать две функции printf и puts . В функции printf в качестве формата передается «%s». Удобство использования этой функции заключается в том, что помимо строки можно сразу выводит данные других типов. Особенность функции puts заключается в том, что после вывода строки автоматически происходит переход на следующую строку.

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

Для преобразования строк в языке Си предусмотрена библиотека string. Каждая из функций имеет свой формат записи (прототип).

Наиболее используемые функции рассмотрены в этой статье. — читать

Пример программ(листинг) работающей со строками

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

Что такое строки?

Отметим, что наряду со строками в стиле С, которые, по сути, являются простыми массивами, есть также строковые литералы, такие как этот "literal" . В действительности, что строки, что литералы — это просто наборы символов, расположенных рядом в памяти компьютера. Но между массивами и литералами все таки есть разница, литералы нельзя изменять и строки — можно.

Любая функция, которая принимает строку в стиле С, также может принимать в качестве параметра — литерал. В си также есть некоторые сущности, которые могут выглядеть как строки, хотя, на самом деле, они таковыми не являются. Я сейчас говорю о символах, они заключены в одинарные кавычки, вот пример — "а" , как видите, это не строка. Символ можно, в определенном месте, присвоить строке, но символы не могут быть обработаны в виде строки. Если вы помните, массивы работают как указатели, поэтому, если вы передаете один символ в строку, это будет считаться ошибкой.

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

"Это статическая строка"

Вы еще не забыли про специфику строк, которая упоминалась немного выше? Так вот, Си-строки всегда должны завершаться нулевым символом, буквально — "\0" . Поэтому, чтобы объявить строку, состоящую из 49 букв, необходимо зарезервировать дополнительную ячейку под нулевой символ:

Char myString;

Как видно из примера, длинна массива — 50 символов, 49 из которых займет строка и один, последний займет нулевой символ. Важно помнить, что в конце си-строк всегда должен быть нуль-символ, точно так же как и в конце каждого предложения есть точка. Хотя нуль символ не отображается при выводе строки, он все-равно занимает место в памяти. Поэтому, технически, в массиве из пятидесяти элементов вы смогли бы сохранить только 49 букв, потому что, последний символ нужен для завершения строки. Кроме того, указатели также могут быть использованы в качестве строки. Если вы читали статью про , вы можете сделать нечто подобное:

Char *myString; // указатель типа char myString = malloc(sizeof(*myString) * 64); // выделение памяти

В этом примере мы выделили 64 ячейки в памяти для массива myString . Для высвобождения памяти воспользуйтесь функцией free() .

Free(myString);

Использование строк

Строки полезно использовать тогда, когда вам необходимо выполнять различные операции с текстовой информацией. Например, если вы хотите, чтобы пользователь вводил имя в программу, вы должны использовать строку. Использование функции scanf() для ввода строки — работает, но это может привести к переполнению буфера. Ведь входная строка может оказаться больше, чем размер строки-буфера. Есть несколько способов для решения этой проблемы, но самый простой способ — это использовать , которая объявлена в заголовочном файле .

Когда считывает входные данные от пользователя, она будет читать все символы, кроме последнего. После этого в конец считанной строки, поместит нулевой терминатор. Функция fgets() будет cчитывать символы до тех пор, пока пользователь не нажмет Enter . Давайте посмотрим пример использования fgets() :

#include int main() { char myString; // длинная строка printf("Введите длинную строку: "); fgets(myString, 100, stdin); // считываем из потока ввода строку printf("Вы ввели следующую строку: %s", myString); getchar(); }

Первым параметром для fgets() является строка, второй параметр — размер строки и третий параметр — это указатель на входной поток данных.

Результат работы программы:

<ВВОД>...

Как видите, из вывода программы, во входную строку попал символ новой строки — "\n" . Так случилось из-за того, что fgets() считала в строку myString нажатие кнопки Enter и завершила работу. Это означает, что вам может понадобиться вручную удалить символ новой строки. Один из способов сделать это, посимвольный перебор. Давайте доработаем программу и удалим символ новой строки:

#include int main() { char myString; // длинная строка printf("Введите длинную строку: "); fgets(myString, 100, stdin); // читываем из потока ввода строку int i; for (i = 0; i < 100; i++) { if (myString[i] == "\n") { myString[i] = "\0"; break; } } printf("Вы ввели следующую строку: %s", myString); getchar(); }

Обратите внимание, что если входная строка содержит меньше 100 символов, то в строку попадет и символ новой строки. Поэтому мы можем удалить этот символ, используя простой перебор. В программу мы добавили цикл, в котором перебираем символы строки, строки 12-19 . И когда нам встречается символ новой строки, мы его заменяем нулевым символом, строка 16 . Результат работы программы:

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

На этом пока все. В следующей статье я расскажу вам о специальных функциях для работы со строками.

P.S.: Все мы любим смотреть разные видео-записи, но иногда бывает так, что не всегда получается воспроизвести некоторые форматы видео-файлов. Так вот, решить эту проблему можно с помощью программы — xilisoft converter ultimate . Вы без труда сможете быстро переконвертировать видео из одного формата в другой. Кроме того, эта программа умеет конвертировать еще и аудио-файлы, и анимированные изображения.

Строки в C++

Строка - последовательность (массив) символов. Если в выражении встречается одиночный символ, он должен быть заключен в одинарные кавычки . При использовании в выражениях строка заключается в двойные кавычки. Признаком конца строки является нулевой символ \0 . В C++ строки можно описать с помощью символов (массив элементов типа char ), в котором следует предусмотреть место для хранения признака конца строки.

Например, описание строки из 25 символов должно выглядеть так:

Можно описать и массив строк:

Определен массив из 3 строк по 25 байт в каждой.

Для работы с указателями можно использовать (char * ). Адрес первого символа будет начальным значением указателя.

Рассмотрим пример объявления и вывода строк.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

#include «stdafx.h»
#include
using namespace std;
int main()
{
setlocale(LC_ALL,«Rus» ) ;
//описываем 3 строки, s3- указатель
char s2[ 20 ] , * s3, s4[ 30 ] ;
cout << «s2=» ; cin >> s2; //ввод строки s2
cout << «s2=» << s2<< endl;
//запись в s3 адреса строки, где хранится s4. Теперь в переменных
//(указателях) s3 и s4 хранится значение одного и того же адреса
s3= s4;
cout << «s3=» ; cin >> s3; //ввод строки s3
//вывод на экран строк s3 и s4, хотя в результате присваивния s3=s4;
//теперь s3 и s4 — это одно и тоже
cout << «s3=» << s3<< endl;
cout << «s4=» << s4<< endl;
system («pause» ) ;
return 0 ;
}

Результат работы программы:

Но следует отметить, что если пользователь введет в одну переменную слова разделенные пробелом, то программа будет работать иначе:

Все дело в том, что функция cin вводит строки до встретившегося пробела. Более универсальной функцией является getline .

cin.getline(char *s, int n);

Предназначена для ввода с клавиатуры строки s с пробелами, в строке не должно быть более n символов. Следовательно, для корректного ввода строк, содержащих пробел, необходимо в нашей программе заменить cin>>s на cin.getline(s, 80) .

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

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

Для преобразования числа в строку можно воспользоваться функцией sprintf из библиотеки stdio.h .

Некоторые функции работы со строками:

Прототип функции Описание функции
size_t strlen(const char *s) вычисляет длину строки s в байтах.
char *strcat(char *dest, const char *scr) присоединяет строку src в конец строки dest, полученная срока возвращается в качестве результата
char *strcpy(char *dest, const char *scr) копирует строку scr в место памяти, на которое указывает dest
char strncat(char *dest, const char *dest, size_t maxlen) присоединяет строку maxlen символов строки src в конец строки dest
char *strncpy(char *dest, const char *scr, size_t maxlen) копирует maxlen символов строки src в место памяти, на которое указывает dest
int ctrcmp(const char *s1, const char *s2) сравнивает две строки в лексикографическом порядке с учетом различия прописных и строчных букв, функция возвращает 0, если строки совпадают, возвращает - 1, если s1 располагается в упорядоченном по алфавиту порядке раньше, чем s2, и 1 - в противоположном случае.
int strncmp(const char *s1, const char *s2, size_t maxlen) сравнивает maxlen символов двух строк в лексикографическом порядке, функция возвращает 0, если строки совпадают, возвращает - 1, если s1 располагается в упорядоченном по алфавиту порядке раньше, чем s2, и 1 - в противоположном случае.
double atof(const char *s) преобразует строку в вещественное число, в случае неудачного преобразования возвращается число 0
long atol(const char *s) преобразует строку в длинное целое число, в случае неудачного преобразования возвращается 0
char *strchr(const char *s, int c); возвращает указатель на первое вхождение символа c в строку, на которую указывает s . Если символ c не найден, возвращается NULL
char *strupr(char *s) преобразует символы строки, на которую указывает s, в символы верхнего регистра, после чего возвращает ее

Тип данных string

Кроме работы со строками, как с массивом символов, в C++ существует специальный тип данных string . Для ввода переменных этого типа можно использовать cin , или специальную функцию getline .

getline(cin, s);

Здесь s - имя вводимой переменной типа string .

При описании переменной этого типа можно сразу присвоить значение этой переменной.

string var(s);

Здесь var - имя переменной, s - строковая константа. В результате этого оператора создается переменная var типа string , и в нее записывается значение строковой константы s . Например,

string v(«Hello»);

Создается строка v , в которую записывается значение Hello .

Доступ к i-му элементу строки s типа string осуществляется стандартным образом s[i] . Над строками типа string определенны следующие операции:

  • присваивания, например s1=s2;
  • объединения строк (s1+=s2 или s1=s1+s2) - добавляет к строке s1 строку s2, результат храниться в строке s1, пример объединения строк:
  • сравнения строк на основе лексикографического порядка: s1=s2, s1!=s2, s1s2, s1<=s2, s1>=s2 - результатом будет логическое значение;

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

  • s.substr(pos, length) - возвращает подстроку из строки s , начиная с номера pos длинной length символов;
  • s.empty() - возвращает значение true, если строка s пуста, false - в противном случае;
  • s.insert(pos, s1) - вставляет строку s1 в строку s , начиная с позиции pos ;
  • s.remove(pos, length) - удаляет из строки s подстроку length длинной pos символов;
  • s.find(s1, pos) - возвращает номер первого вхождения строки s1 в строку s , поиск начинается с номера pos , параметр pos может отсутствовать, в этом случае поиск идет с начала строки;
  • s.findfirst(s1, pos) - возвращает номер первого вхождения любого символа из строки s1 в строку s , поиск начинается с номера pos , который может отсутствовать.

Русский язык для строк

Думаю вы уже заметили, что при выводе русских букв, в консоли появляются «левые» символы. Для того чтобы избежать этого недоразумения, необходимо воспользоваться сторонней функцией CharToOemA . Подключаем библиотеку windows.h , она нужна для того, чтобы наша функция могла преобразовать строки в другую кодировку. Также, нам понадобиться дополнительный символьный массив. Исходный код программы будет выглядеть вот так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

#include «stdafx.h»
#include
#include
using namespace std;
int main()
{ setlocale(LC_ALL,«Rus» ) ;
char s[ 255 ] = { » Меня надо преобразовать « } ;
char * pre= new char [ 255 ] ;
CharToOemA(s, pre) ; //преобразовываем
cout << s;
delete pre;
system («pause>>void» ) ;
return 0 ;
}

Способ только что описанный достаточно не удобен. Но существует более простой вариант решения «русской» проблемы. Как видите, в программе используется функция setlocale(), вместо этого удобнее вписать в главную функцию следующую конструкцию.

Библиотека функций языков С и C++ включает богатый набор функций обработки строк и символов. Строковые функции работают с символьными массивами, завершающимися нулевыми символами. В языке С для использования строковых функций необходимо включить в начало модуля программы заголовочный файл , а для символьных - заголовочный файл . В языке C++ для работы со строковыми и символьными функциями используются заголовки и соответственно. В этой главе для простоты изложения используются имена С-заголовков.

Поскольку в языках С и C++ при выполнении операций с массивами не предусмотрен автоматический контроль нарушения их границ, вся ответственность за переполнение массивов ложится на плечи программиста. Пренебрежение этими тонкостями может привести программу к аварийному отказу.

В языках С и C++ печатаемыми являются символы, отображаемые на терминале. В ASCII-средах они расположены между пробелом(0x20) и тильдой(OxFE). Управляющие символы имеют значения, лежащие в диапазоне между нулем и Ox1F; к ним также относится символ DEL(Ox7F).

Исторически сложилось так, что аргументами символьных функций являются целые значения, из которых используется только младший байт. Символьные функции автоматически преобразуют свои аргументы в тип unsigned char. Безусловно, вы вольны вызывать эти функции с символьными аргументами, поскольку символы автоматически возводятся в ранг целых в момент вызова функции.

В заголовке определен тип size_t, который является результатом применения оператора sizeof и представляет собой разновидность целого без знака.

В версии С99 к некоторым параметрам нескольких функций, первоначально определенных в версии С89, добавлен квалификатор restrict. При рассмотрении каждой такой функции будет приведен ее прототип, используемый в среде С89(а также в среде C++), а параметры с атрибутом restrict будут отмечены в описании этой функции.

Список функций

Проверка на принадлежность

isalnum - Проверка на принадлежность символа к алфавитно-цифровым
isalpha - Проверка на принадлежность символа к буквам
isblank - Проверка пустого символа
iscntrl - Проверка на принадлежность символа к управляющим
isdigit - Проверка на принадлежность символа к цифровым
isgraph - Проверка на принадлежность символа к печатным но не к пробелу
islower - Проверка на принадлежность символа к строчным
isprint - Проверка на принадлежность символа к печатным
ispunct - Проверка на принадлежность символа к знакам пунктуации
isspace - Проверка на принадлежность символа к пробельным
isupper - Проверка на принадлежность символа к прописным
isxdigit - Проверка на принадлежность символа к шестнадцатеричным

Работа с символьными массивами

memchr - Просматривает массив чтобы отыскать первое вхождение символа
memcmp - Сравнивает определённое количество символов в двух массивах
memcpy - Копирует символы из одного массива в другой
memmove - Копирует символы из одного массива в другой с учётом перекрытия массивов
memset - Заполняет определённое количество символов массива заданным

Манипуляции над строками

strcat - Присоединяет копию одной строки к заданной
strchr - Возвращает указатель на первое вхождение младшего байта заданного параметра
strcmp - Сравнивает в лексикографическом порядке две строки
strcoll - Сравнивает одну строку с другой в соответствии с параметром setlocale
strcpy - Копирует содержимое одной строки в другую
strcspn - Возвращает строку в которой отсутствуют заданные символы
strerror - Возвращает указатель на строку содержащую системное сообщение об ошибке
strlen - Возвращает длину строки с завершающим нулевым символом

В современном стандарте C++ определен класс с функциями и свойствами (переменными) для организации работы со строками (в классическом языке C строк как таковых нет, есть лишь массивы символов char):

#include

#include

#include

Для работы со строками также нужно подключить стандартный namespace:

Using namespace std;

В противном случае придётся везде указывать описатель класса std::string вместо string .

Ниже приводится пример программы, работающей со string (в старых си-совместимых компиляторах не работает!):

#include #include #include using namespace std; int main () { string s = "Test"; s.insert (1,"!"); cout << s.c_str() << endl; string *s2 = new string("Hello"); s2->erase(s2->end()); cout << s2->c_str(); cin.get(); return 0; }

Основные возможности, которыми обладает класс string:

  • инициализация массивом символов (строкой встроенного типа) или другим объектом типа string . Встроенный тип не обладает второй возможностью;
  • копирование одной строки в другую. Для встроенного типа приходится использовать функцию strcpy() ;
  • доступ к отдельным символам строки для чтения и записи. Во встроенном массиве для этого применяется операция взятия индекса или косвенная адресация с помощью указателя;
  • сравнение двух строк на равенство. Для встроенного типа используются функции семейства strcmp() ;
  • конкатенация (сцепление) двух строк, дающая результат либо как третью строку, либо вместо одной из исходных. Для встроенного типа применяется функция strcat() , однако чтобы получить результат в новой строке, необходимо последовательно задействовать функции strcpy() и strcat() , а также позаботиться о выделении памяти;
  • встроенные средства определения длины строки (функции-члены класса size() и l ength()). Узнать длину строки встроенного типа можно только вычислением с помощью функции strlen() ;
  • возможность узнать, пуста ли строка.

Рассмотрим эти базовые возможности более подробно.

Инициализация строк при описании и длина строки (не включая завершающий нуль-терминатор):

String st("Моя строка\n"); cout << "Длина " << st << ": " << st.size() << " символов, включая символ новой строки\n";

Строка может быть задана и пустой:

String st2;

Для проверки того, пуста ли строка , можно сравнить ее длину с 0:

If (! st.size()) // пустая

или применить метод empty() , возвращающий true для пустой строки и false для непустой:

If (st.empty()) // пустая

Третья форма создания строки инициализирует объект типа string другим объектом того же типа:

String st3(st);

Строка st3 инициализируется строкой st . Как мы можем убедиться, что эти строки совпадают ? Воспользуемся оператором сравнения (==):

If (st == st3) // инициализация сработала

Как скопировать одну строку в другую ? С помощью обычной операции присваивания:

St2 = st3; // копируем st3 в st2

Для сцепления строк используется операция сложения (+) или операция сложения с присваиванием (+=). Пусть даны две строки:

String s1("hello, "); string s2("world\n");

Мы можем получить третью строку, состоящую из конкатенации первых двух, таким образом:

String s3 = s1 + s2;

Если же мы хотим добавить s2 в конец s1 , мы должны написать:

S1 += s2;

Операция сложения может сцеплять объекты класса string не только между собой, но и со строками встроенного типа. Можно переписать пример, приведенный выше, так, чтобы специальные символы и знаки препинания представлялись встроенным типом char * , а значимые слова – объектами класса string:

Const char *pc = ", "; string s1("hello"); string s2("world"); string s3 = s1 + pc + s2 + "\n"; cout << endl << s3;

Подобные выражения работают потому, что компилятор "знает", как автоматически преобразовывать объекты встроенного типа в объекты класса string . Возможно и простое присваивание встроенной строки объекту string:

String s1; const char *pc = "a character array"; s1 = pc; // правильно

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

Char *str = s1; // ошибка компиляции

Чтобы осуществить такое преобразование, необходимо явно вызвать функцию-член с названием c_str() ("строка Си"):

Const char *str = s1.c_str();

Функция c_str() возвращает указатель на символьный массив, содержащий строку объекта string в том виде, в каком она находилась бы во встроенном строковом типе. Ключевое слово const здесь предотвращает "опасную" в современных визуальных средах возможность непосредственной модификации содержимого объекта через указатель.

К отдельным символам объекта типа string , как и встроенного типа, можно обращаться с помощью операции взятия индекса. Вот, например, фрагмент кода, заменяющего все точки символами подчеркивания:

String str("www.disney.com"); int size = str.size(); for (int i = 0; i < size; i++) if (str[i] == ".") str[ i ] = "_"; cout << str;

Replace(str.begin(), str.end(), ".", "_");

Правда, здесь использован не метод replace класса string , а одноимённый алгоритм:

#include

Поскольку объект string ведет себя как контейнер, к нему могут применяться и другие алгоритмы. Это позволяет решать задачи, не решаемые напрямую функциями класса string .

Ниже приводится краткое описание основных операторов и функций класса string , ссылки в таблице ведут к русскоязычным описаниям в интернете. Более полный список возможностей класса string можно получить, например, в Википедии или на сайте cplusplus.com .

Задание символов в строке

operator=

присваивает значения строке

assign

назначает символы строке

Доступ к отдельным символам

at

получение указанного символа с проверкой выхода индекса за границы

operator

получение указанного символа

front

получение первого символа

back

получение последнего символа

data

возвращает указатель на первый символ строки

c_str

возвращает немодифицируемый массив символов С , содержащий символы строки

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

empty

проверяет, является ли строка пустой

size
length

возвращает количество символов в строке

max_size

возвращает максимальное количество символов

reserve

резервирует место под хранение

Операции над строкой

clear

очищает содержимое строки

insert

вставка символов

erase

удаление символов

push_back

добавление символа в конец строки

pop_back

удаляет последний символ

append

operator+=

добавляет символы в конец строки

compare

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

replace

заменяет каждое вхождение указанного символа

substr

возвращает подстроку

copy

копирует символы

resize

изменяет количество хранимых символов