В языке С строки являются обычными массивами фиксированного размера из символов ``char`` (однобайтные символы) или ``wchar_t`` (символы Unicode). Признаком конца строки является нулевой символ ``'\0'``, хранение которого нужно учитывать при определении размера массива. Определение
```c
char s[]="ABC";
```
эквивалентно
```c
char s[]={'A','B','C','\0'}; // массив из 4 символов
```
Аналогично последовательность символов в кавычках ``"ABC"`` в операторах программы интерпретируется компилятором как массив-значение: ``(static const char []){'A','B','C','\0'}``
Действия над строками в языке С определены как функции в заголовочных файлах ``<string.h>``, ``<wchar.h>``, ``<stdio.h>``. Основными недостатками этих функций является низкая эффективность, сложный код, необходимость проверки не только переполнения выделенной памяти, но и выхода за пределы текущей длины строки.
Гораздо удобнее использовать строки в языке С++, определенные в заголовочном файле ``<string>``
Функция | Строки ``char`` | Строки ``wchar_t``| Строки С++
----|----|----|---
Определение строк|``char s1[101], // строка длиной 100 символов + место для '\0'``\
``s2[101]="ABC"; // с заданием начального значения``\
``char* sr; // для результатов поиска``|``wchar_t s1[101], s2[101]=L"ABC";``\
``wchar_t* sr;``|``string s1, s2="ABC"; // wstring s1, s2=L"ABC";``
Вспомогательные объявления|``size_t len, // длина строки``\
``pos=2, // позиция в строке``\
``n=5; //количество символов``\
``int a; double b; // для преобразований строка<->число``
Длина строки | ``len=strlen(s2);`` | ``len=wcslen(s2);``| ``len=s2.length(); // len=s2.size();``
Проход по всем символам строки|``for(int i=0; s1[i]; ++i) // s1[i]``|``for(int i=0; s1[i]; ++i) // s1[i]``|``for(int i=0; i<s1.size(); ++i) // s1[i]``
Копирование строки | ``strcpy(s1,s2);`` | ``wcscpy(s1,s2);``|``s1=s2;``
Заполнение строки символом| ``memset(s1,'A',n); s1[n]=0;`` | ``wmemset(s1,L'A',n); s1[n]=0;``|``s1=string(n,'A');``
Подстрока с ``pos`` длиной ``n`` (или до конца строки)|``strncpy(s1,s2+pos,n); s1[n]=0;``|``wcsncpy(s1,s2+pos,n); s1[n]=0;``|``s1=s2.substr(pos,n);``
Добавление строки | ``strcat(s1,s2);`` | ``wcscat(s1,s2);``| ``s1+=s2;``
Добавление символа | ``len=strlen(s1); s1[len++]='A'; s1[len]=0;`` | ``len=wcslen(s1); s1[len++]='A'; s1[len]=0;``| ``s1+='A';``
Удаление подстроки с ``pos`` длиной ``n`` (или до конца строки)|``if(pos+n<len) memmove(s1+pos,s1+pos+n,len+1-pos-n);``\
``else s1[pos]=0;``|``if(pos+n<len) wmemmove(s1+pos,s2+pos+n,len+1-pos-n);``\
``else s1[pos]=0;``|``s1.erase(pos,n);``
Вставка строки|``n=strlen(s2);``\
``memmove(s1+pos+n,s1+pos,len+1-pos);``\
``strncpy(s1+pos,s2,n);``|``n=wcslen(s2);``\
``wmemmove(s1+pos+n,s1+pos,len+1-pos);``\
``wcsncpy(s1+pos,s2,n);``|``s1.insert(pos,s2);``
Сравнение строк | ``if(strcmp(s1,s2)>=0) // s1>=s2`` | ``if(wcscmp(s1,s2)>=0)`` | ``if(s1>=s2)``
Поиск подстроки/символа | ``sr=strstr(s1,s2); // sr=strchr(s1,'A');``\
``if(sr) { pos=sr-s1; ... // s2 найдена в позиции pos``\
``else { ... // s2 не найдена``|``sr=wcsstr(s1,s2); // sr=wcschr(s1,L'A');``\
``if(sr) { pos=sr-s1; ... } else {...}``| ``pos=s1.find(s2); // pos=s1.find('A');``\
``if(pos!=string::npos) {/* найдена */}``\
``else { /* нет */}``
Поиск подстроки/символа, начиная с pos | ``sr=strstr(s1+pos,s2); // sr=strchr(s1+pos,'A');``\
далее аналогично|``sr=wcsstr(s1+pos,s2); // sr=wcschr(s1+pos,L'A');``|``pos=s1.find(s2,pos); // pos=s1.find('A',pos);``
Ввод слова | ``scanf("%100s",s1);`` | ``wscanf(L"%100ls",s1);`` | ``cin>>s1;``
Ввод строки до '\n' | ``if(scanf("%100[^\n]", s1) != 1) s1[0] = 0;``\
``getchar();`` | ``if(wscanf(L"%100l[^\n]", s1) != 1) s1[0] = 0;``\
``getwchar();`` | ``getline(cin,s1);``
Вывод строки | ``printf("%s",s1);`` | ``wprintf(L"%ls",s1);`` | ``cout<<s1;``
Преобразование строки в число| ``sscanf(s1,"%d",&a); // или a=atoi(s1);``\
``sscanf(s1,"%lf",&b); // или b=atof(s1);``|``swscanf(s1,L"%d",&a);``\
``swscanf(s1,L"%lf",&b);``|``a=stoi(s1);``\
``b=stod(s1);``
Преобразование числа в строку| ``sprintf(s1,"%d",a);``\
``sprintf(s1,"%lg",b);``|``swprintf(s1,L"%d",a);``\
``swprintf(s1,L"%lg",b);``|``s1=to_string(a);``\
``s1=to_string(b);``
*Замечания:*
* ``strcpy/strncpy`` используется только для копирования из одной строки в *другую* (``strcpy`` до конца строки, ``strncpy`` -- не более `n` символов, в том числе '\0'), ``memmove`` -- для копирования части строки, возможно в *ту же строку* (также как у массивов).
* при обнаружении конца файла ``scanf`` вернет ``EOF``
* после ввода слова можно проверять какой следующий символ идет после слова, вызывая ``getchar()`` или ``cin.get()``, функция возвращает ``' '``, если есть еще слово в этой строке, или ``'\n'`` -- конец строки или EOF -- конец файла
* в C++ результат ввода можно указать в качестве условия: \
``if(cin>>s1) //успешный ввод``\
``else // конец файла``
```run-c
#include <stdio.h>
#include <string.h>
// Вывод всех строк в обратном порядке
int main() {
char s1[101];
for(;;) {
if(scanf("%100[^\n]", s1) != 1) s1[0] = 0;
if(getchar()==EOF) break;
size_t len=strlen(s1);
for(int i=len-1;i>=0;--i)
printf("%c",s1[i]);
printf("\n");
}
}
<<
Коту тащат уток.
Was it a car or a cat I saw?
```
Для распознавания символов в С и С++ используются функции, объявленные в заголовочных файлах ``<ctype.h>``,``<wctype.h>``. Аргумент типа ``char`` должен быть преобразован в ``unsigned char`` (``char8_t``).
Для однобайтных символов на результат будет влиять выбор кодировки:\
``setlocale(LC_CTYPE|LC_COLLATE, "ru_RU.cp1251");``
Функция | ``unsigned char`` | ``wchar_t``
----|----|----
Пробельный символ (``' ', '\n', '\t'``, ...)|``isspace(c)``|``iswspace(c)``
Цифра|``isdigit(c)``|``iswdigit(c)``
Буква|``isalpha(c)``|``iswalpha(c)``
Буква или цифра|``isalnum(c)``|``iswalnum(c)``
Строчная буква|``islower(c)``|``iswlower(c)``
Прописная буква|``isupper(c)``|``iswupper(c)``
В строчную букву|``c=tolower(c);``|``c=towlower(c);``
В прописную букву|``c=toupper(c);``|``c=towupper(c);``
```run-c
#include <stdio.h>
#include <string.h>
// Первая строка содержит запрещенные буквы в верхнем регистре
// Вторая строка число N
// Далее N строк, для каждой строки вывести yes, если строка не содержит запрещенных букв, иначе no
int main() {
char dis[101],s[101];
int n;
scanf("%100s%d%*c",dis,&n); // ввести слово, число и символ '\n' после числа
for(int i=0;i<n;++i) {
if(scanf("%100[^\n]", s) != 1) s[0] = 0;
getchar();
int fl=1;
for(int j=0;dis[j];++j)
if(strchr(s,dis[j]) || strchr(s,tolower((unsigned char)dis[j]))) {
fl=0;
break;
}
if(fl) printf("yes\n");
else printf("no\n");
}
}
<<
QYFJX
2
Oma, Ich habe nicht die Uhr geklaut.
Das Raumschiff ist kaputt. Hilfe ist notwendig.
```
В ``<stdlib.h>`` определены 2 функции для преобразования из wchar_t в символы текущей кодировки и обратно. Если установлена кодировка UTF8, то 1 символ может занимать в массиве от 1 до 4 байт (1 байт -- символы ASCII, 2 байта -- русские буквы, 3 байта -- иероглифы, 4 байта -- пиктограммы).
Для операций над строками с многобайтными символами можно использовать функции из ``<string.h>``, но нужно учитывать, что в качестве аргументов многим функциям нужно указывать номер байта, а не номер символа, и номер байта будет результатом поиска.
```run-c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>
int main() {
setlocale(LC_ALL, "ru_RU.utf8");
wchar_t a[]=L"z\u00df\u6c34"; // строка из 3 символов: z, греческая бета и иероглиф
char b[100];
wchar_t c[10];
size_t alen=wcslen(a);
size_t blen=wcstombs(b, a, sizeof(b)); // преобразование из Unicode в UTF8
if(blen==-1) return 1; // ошибка
for(int i=0; i<alen; ++i)
printf("a[%d]=%x\n",i,a[i]);
for(int i=0; i<blen; ++i)
printf("b[%d]=%x\n",i,(unsigned char)b[i]);
strcat(b,u8"+\u0462"); // добавляем строку из 2 символов в кодировке UTF8
printf("len=%d\n",(int)strlen(b)); // длина строки увеличивается на 3 байта
size_t clen=mbstowcs(c, b, sizeof(c)); // преобразование из UTF8 в Unicode
if(clen==-1) return 1; // ошибка
for(int i=0; i<clen; ++i)
printf("c[%d]=%x\n",i,(int)c[i]);
}
```