Символьная строка в си. Работа со строками

Строки в 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(), вместо этого удобнее вписать в главную функцию следующую конструкцию.

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

char str = "Это просто строка";

Эту же строчку для большего понимания можно записать вот так:

char str = {"Э","т","о"," ","п","р","о","с","т","о","","с","т","р","о","к","а"};

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

А теперь давайте попробуем работать со строками в c . На вводных уроках мы разбирали, что символы относятся к целочисленным типам, т.е. каждый символ имеет свое числовое значение. Вот пример и его решение:

  1. требуется перевести введенное слово в верхний регистр:
  2. #include
    #include

    Int main()
    {
    char str = "sergey";

    str[i] -= 32;
    }
    for (int i=0; str[i] != "\0";i++){
    printf ("%c", str[i]);
    }
    getch();

    Return 0;
    }

    для получения кода числа просто воспользуйтесь в функции printf спецификатором %d. Да, и еще один важный момент: окончанием любой строки является нуль-терминатор, который обозначается специальным символом - "\0".

Еще одним способом указания строки является объявление ее через char*. Вот пример:

char *str = "provod";

Т.е. создается указатель на строку, который располагается где-то в памяти.

А вот как можно вводить строки через, нам уже родной, опертаор scanf:

char str; scanf("%s", str);

Тут две тонкости:

  1. знак взятия адреса тут не нужен, так как имя массива, как мы уже знаем, и является адресом
  2. Длина вводимой строки не должна превышать 15 символов, так как последним обязательно должен быть нуль-терминатор. Причем компилятор сам заполнит этот символ после последнего введенного вашего символа.

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

Иногда вам может понадобиться перевести строку в другой тип данных. Для перевода строк в другие типы существует библиотека stdlib. Вот ее функции:

  1. int atoi (char *str)
  2. long atol (char *str)
  3. double atof (char *str)

Иногда эти функции очень помогают, например, когда вам надо извлечь из строки год или цифровое значение. Работа со строками в c (си) является очень важной темой, поэтому постарайтесь вникнуть в этот урок.

Пожалуйста, приостановите работу AdBlock на этом сайте.

Итак, строки в языке Си. Для них не предусмотрено отдельного типа данных, как это сделано во многих других языках программирования. В языке Си строка – это массив символов. Чтобы обозначить конец строки, используется символ "\0" , о котором мы говорили в прошлой части этого урока. На экране он никак не отображается, поэтому посмотреть на него не получится.

Создание и инициализация строки

Так как строка – это массив символов, то объявление и инициализация строки аналогичны подобным операциям с одномерными массивами.

Следующий код иллюстрирует различные способы инициализации строк.

Листинг 1.

Char str; char str1 = {"Y","o","n","g","C","o","d","e","r","\0"}; char str2 = "Hello!"; char str3 = "Hello!";

Рис.1 Объявление и инициализация строк

В первой строке мы просто объявляем массив из десяти символов. Это даже не совсем строка, т.к. в ней отсутствует нуль-символ \0 , пока это просто набор символов.

Вторая строка. Простейший способ инициализации в лоб. Объявляем каждый символ по отдельности. Тут главное не забыть добавить нуль-символ \0 .

Третья строка – аналог второй строки. Обратите внимание на картинку. Т.к. символов в строке справа меньше, чем элементов в массиве, остальные элементы заполнятся \0 .

Четвёртая строка. Как видите, тут не задан размер. Программа его вычислит автоматически и создаст массив символов нужный длины. При этом последним будет вставлен нуль-символ \0 .

Как вывести строку

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

Листинг 2.

#include int main(void) { char str; char str1 = {"Y","o","n","g","C","o","d","e","r","\0"}; char str2 = "Hello!"; char str3 = "Hello!"; for(int i = 0; i < 10; i = i + 1) printf("%c\t",str[i]); printf("\n"); puts(str1); printf("%s\n",str2); puts(str3); return 0; }


Рис.2 Различные способы вывода строки на экран

Как видите, есть несколько основных способов вывести строку на экран.

  • использовать функцию printf со спецификатором %s
  • использовать функцию puts
  • использовать функцию fputs , указав в качестве второго параметра стандартный поток для вывода stdout .

Единственный нюанс у функций puts и fputs . Обратите внимание, что функция puts переносит вывод на следующую строку, а функция fputs не переносит.

Как видите, с выводом всё достаточно просто.

Ввод строк

С вводом строк всё немного сложнее, чем с выводом. Простейшим способом будет являться следующее:

Листинг 3.

#include int main(void) { char str; gets(str); puts(str); return 0; }

Функция gets приостанавливает работу программы, читает строку символов, введенных с клавиатуры, и помещает в символьный массив, имя которого передаётся функции в качестве параметра.
Завершением работы функции gets будет являться символ, соответствующий клавише ввод и записываемый в строку как нулевой символ.
Заметили опасность? Если нет, то о ней вас любезно предупредит компилятор. Дело в том, что функция gets завершает работу только тогда, когда пользователь нажимает клавишу ввод. Это чревато тем, что мы можем выйти за рамки массива, в нашем случае - если введено более 20 символов.
К слову, ранее ошибки переполнения буфера считались самым распространенным типом уязвимости. Они встречаются и сейчас, но использовать их для взлома программ стало гораздо сложнее.

Итак, что мы имеем. У нас есть задача: записать строку в массив ограниченного размера. То есть, мы должны как-то контролировать количество символов, вводимых пользователем. И тут нам на помощь приходит функция fgets :

Листинг 4.

#include int main(void) { char str; fgets(str, 10, stdin); puts(str); return 0; }

Функция fgets принимает на вход три аргумента: переменную для записи строки, размер записываемой строки и имя потока, откуда взять данные для записи в строку, в данном случае - stdin . Как вы уже знаете из 3 урока, stdin – это стандартный поток ввода данных, обычно связанный с клавиатурой. Совсем необязательно данные должны поступать именно из потока stdin , в дальнейшем эту функцию мы также будем использовать для чтения данных из файлов.

Если в ходе выполнения этой программы мы введем строку длиннее, чем 10 символов, в массив все равно будут записаны только 9 символов с начала и символ переноса строки, fgets «обрежет» строку под необходимую длину.

Обратите внимание, функция fgets считывает не 10 символов, а 9 ! Как мы помним, в строках последний символ зарезервирован для нуль-символа.

Давайте это проверим. Запустим программу из последнего листинга. И введём строку 1234567890 . На экран выведется строка 123456789 .


Рис.3 Пример работы функции fgets

Возникает вопрос. А куда делся десятый символ? А я отвечу. Он никуда не делся, он остался в потоке ввода. Выполните следующую программу.

Листинг 5.

#include int main(void) { char str; fgets(str, 10, stdin); puts(str); int h = 99; printf("do %d\n", h); scanf("%d",&h); printf("posle %d\n", h); return 0; }

Вот результат её работы.


Рис.4 Непустой буфер stdin

Поясню произошедшее. Мы вызвали функцию fgets . Она открыла поток ввода и дождалась пока мы введём данные. Мы ввели с клавиатуры 1234567890\n (\n я обозначаю нажатие клавиша Enter ). Это отправилось в поток ввода stdin . Функция fgets , как и полагается, взяла из потока ввода первые 9 символов 123456789 , добавила к ним нуль-символ \0 и записала это в строку str . В потоке ввода осталось ещё 0\n .

Далее мы объявляем переменную h . Выводим её значение на экран. После чего вызываем функцию scanf . Тут-то ожидается, что мы можем что-то ввести, но т.к. в потоке ввода висит 0\n , то функция scanf воспринимает это как наш ввод, и записывается 0 в переменную h . Далее мы выводим её на экран.

Это, конечно, не совсем такое поведение, которое мы ожидаем. Чтобы справиться с этой проблемой, необходимо очистить буфер ввода после того, как мы считали из него строку, введённую пользователем. Для этого используется специальная функция fflush . У неё всего один параметр – поток, который нужно очистить.

Исправим последний пример так, чтобы его работа была предсказуемой.

Листинг 6.

#include int main(void) { char str; fgets(str, 10, stdin); fflush(stdin); // очищаем поток ввода puts(str); int h = 99; printf("do %d\n", h); scanf("%d",&h); printf("posle %d\n", h); return 0; }

Теперь программа будет работать так, как надо.


Рис.4 Сброс буфера stdin функцией fflush

Подводя итог, можно отметить два факта. Первый. На данный момент использование функции gets является небезопасным, поэтому рекомендуется везде использовать функцию fgets .

Второй. Не забывайте очищать буфер ввода, если используете функцию fgets .

На этом разговор о вводе строк закончен. Идём дальше.

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

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

Отметим, что наряду со строками в стиле С, которые, по сути, являются простыми массивами, есть также строковые литералы, такие как этот "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++ включает богатый набор функций обработки строк и символов. Строковые функции работают с символьными массивами, завершающимися нулевыми символами. В языке С для использования строковых функций необходимо включить в начало модуля программы заголовочный файл , а для символьных - заголовочный файл . В языке 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 - Возвращает длину строки с завершающим нулевым символом



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: