Глиф Учебники

Урок 6. Строки std::string

Курс «C++» · урок 6 из 10 · 3 минуты чтения

Текст в C++ хранится в строках — переменных типа string. Строка умеет узнавать свою длину, склеиваться с другими строками, искать в себе подстроку и многое другое. Для неё нужен #include <string>.

Создание, длина, символы

C++
#include <iostream>
#include <string>
using namespace std;

int main() {
    string s = "Hello";
    string t = "world";
    string u = s + ", " + t + "!";
    cout << u << "\n";
    cout << u.size() << "\n";
    cout << u[0] << u[7] << "\n";
    u[0] = 'J';
    cout << u << "\n";
    return 0;
}
Вывод
Hello, world!
13
Hw
Jello, world!
string u = s + ", " + t + "!"; s ", " t "!" H 0 e 1 l 2 l 3 o 4 , 5 6 w 7 o 8 r 9 l 10 d 11 ! 12 u.size() = 13 u[0] = 'H', u[7] = 'w' индексы с нуля, пробел — тоже символ
Строка u, склеенная из s, ", ", t и "!", — 13 символов с индексами от 0 до 12: под индексом 0 стоит H, под индексом 7 — w, а пробел тоже считается символом.

Пустая строка — "", у неё size() равен 0, а s.empty() — true.

Ввод строки

cin >> s читает одно слово — до первого пробела или перевода строки. Целую строку с пробелами читает getline(cin, s). У getline есть ловушка после cin >>, она разобрана в справке Как прочитать строку с пробелами.

Символы и их коды

Каждый символ — это число, его код. Латинские буквы, цифры и знаки препинания имеют коды из таблицы ASCII: 'A' — 65, 'a' — 97, '0' — 48. Буквы и цифры идут в таблице подряд, поэтому с символами можно считать:

C++
#include <iostream>
using namespace std;

int main() {
    char c = 'A';
    cout << c + 1 << "\n";
    cout << char(c + 1) << "\n";
    char d = '7';
    int digit = d - '0';
    cout << digit * 2 << "\n";
    return 0;
}
Вывод
66
B
14

c + 1 — уже число (66), а char(c + 1) превращает его обратно в символ. d - '0' — частый приём: из символа цифры получается сама цифра.

символ и его код (таблица ASCII) цифры 0 48 1 49 … 7 55 8 56 9 57 большие буквы A 65 B 66 C 67 … Y 89 Z 90 маленькие буквы a 97 b 98 c 99 … y 121 z 122 '7' - '0' = 7 55 − 48 = 7 char('A' + 1) = 'B' 65 + 1 = 66 "Zebra" < "apple" код 'Z' 90 меньше кода 'a' 97
Цифры, большие и маленькие латинские буквы идут в таблице кодов подряд, поэтому '7' - '0' даёт 7, char('A' + 1) — B, а "Zebra" меньше "apple": код Z 90 меньше кода a 97.

Проверить символ можно сравнениями (c >= '0' && c <= '9' — цифра) или функциями из <cctype>:

ФункцияЧто проверяет или делает
isdigit(c)цифра ли это
isalpha(c)латинская буква ли это
isspace(c)пробел, табуляция, перевод строки
toupper(c), tolower(c)та же буква большая или маленькая
C++
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

int main() {
    string s;
    cin >> s;
    int letters = 0, digits = 0;
    for (char& c : s) {
        if (isdigit(c)) {
            digits++;
        } else if (isalpha(c)) {
            letters++;
            c = toupper(c);
        }
    }
    cout << letters << " " << digits << " " << s << "\n";
    return 0;
}
Ввод
abc123x
Вывод
4 3 ABC123X

Часть строки и поиск

C++
#include <iostream>
#include <string>
using namespace std;

int main() {
    string date = "2024-11-05";
    string year = date.substr(0, 4);
    string month = date.substr(5, 2);
    cout << year << " " << month << "\n";
    cout << date.find('-') << "\n";
    cout << date.find("11") << "\n";
    if (date.find("abc") == string::npos) {
        cout << "not found\n";
    }
    return 0;
}
Вывод
2024 11
4
5
not found
string date = "2024-11-05"; date.substr(0, 4) = "2024" date.substr(5, 2) = "11" 2 0 0 1 2 2 4 3 - 4 1 5 1 6 - 7 0 8 5 9 date.find('-') = 4 date.find("11") = 5 date.find("abc") = string::npos — не найдено
В строке 2024-11-05 substr(0, 4) берёт четыре символа с индекса 0, substr(5, 2) — два с индекса 5; find возвращает индекс первого вхождения, а если ничего нет — string::npos.

Ещё полезное: s.erase(pos, len) удаляет кусок, s.insert(pos, t) вставляет строку t, s.back() — последний символ, s.pop_back() — удалить последний символ.

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

Строки сравниваются обычными ==, !=, <, >. Порядок — словарный (лексикографический): по первому различающемуся символу, точнее по его коду.

C++
#include <iostream>
#include <string>
using namespace std;

int main() {
    string a = "apple", b = "banana", c = "Zebra";
    cout << (a < b) << "\n";
    cout << (c < a) << "\n";
    cout << (string("10") < string("9")) << "\n";
    return 0;
}
Вывод
1
1
1

Две неожиданности: "Zebra" меньше "apple", потому что код большой Z (90) меньше кода маленькой a (97). А "10" меньше "9", потому что '1' меньше '9': строки из цифр сравниваются не как числа. Перевести строку в число и обратно помогает справка Как перевести строку в число.

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

Функция reverse из <algorithm> переворачивает строку. Палиндром — слово, которое одинаково читается в обе стороны:

C++
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string s;
    cin >> s;
    string r = s;
    reverse(r.begin(), r.end());
    if (r == s) {
        cout << "palindrome\n";
    } else {
        cout << "not palindrome\n";
    }
    return 0;
}
Ввод
level
Вывод
palindrome

s.begin() и s.end() — начало и конец строки. Так же, парой «начало — конец», работают и другие функции стандартной библиотеки — о них урок STL: sort, map и set.

Русские буквы

string хранит не буквы, а байты. В кодировке UTF-8 (она обычна в Linux, macOS и для g++) латинская буква занимает один байт, а русская — два:

C++
#include <iostream>
#include <string>
using namespace std;

int main() {
    string en = "world";
    string ru = "мир";
    cout << en.size() << " " << ru.size() << "\n";
    return 0;
}
Вывод
5 6

Поэтому с русским текстом size(), s[i], reverse и toupper работают не по буквам. Для задач с русскими словами нужны отдельные средства; на олимпиадах текст обычно латинский.

Коротко

Проверьте себя

1. Что выведет cout << string("abcdef").substr(2, 3);?
2. Как проверить, что подстрока не найдена?
3. Как получить число 5 из символа '5'?
4. Какое сравнение истинно?