JavaRush /Курсы /C++ SELF /Строки — std::string, конкатенация, длина

Строки — std::string, конкатенация, длина

C++ SELF
2 уровень , 2 лекция
Открыта

1. Введение

Когда вы только начинаете программировать, легко попасть в иллюзию, что «главное — числа». Ну правда: оценки, деньги, возраст, счётчики — везде цифры. Но как только вы захотите сделать программу хоть немного дружелюбной к человеку, внезапно выясняется: человек общается словами. Имя, фамилия, город, комментарий к заказу, название фильма — всё это текст, то есть строка.

Когда С++ только появился, то типа строка (string) в нем не было - строку воспринимали просто как набор символов (тип char). Однако со временем выяснилось, что это очень неудобно, и было решено создать отдельный тип string и добавить его в стандартнутю (STD) библиотеку С++. Так в C++ появился тип std::string.

Его можно воспринимать как контейнер для последовательности символов: внутри лежат буквы, пробелы, знаки пунктуации. И, что особенно приятно, стандартная библиотека даёт нам готовые операции для строк: склеивать, узнавать длину, брать символ по номеру.

Чтобы покачать работу с std, мы будем развивать одно небольшое приложение по мере курса: «консольная визитка». Пока оно будет просто собирать красивую строку визитки и печатать её. Сегодня мы добавим туда имя и пару текстовых деталей.

2. Первая строка: подключаем <string>

Сейчас будет момент, который сначала кажется мелочью, а потом становится второй натурой: чтобы использовать std::string, обычно нужен заголовок <string>. Да, в некоторых компиляторах «как-то работает и без него», но это плохая привычка: лучше подключать то, что вы используете.

Начнём с простого: создадим строку из строкового литерала "..." и выведем её.

#include <iostream>
#include <string>

int main() {
    std::string course = "C++ for beginners";
    std::cout << course << '\n'; // C++ for beginners
}

Здесь важна идея: std::string — это тип, как int, только для текста. Мы объявили переменную course и положили в неё текст. Дальше она ведёт себя как «значение», которое можно передавать в вывод.

Строка "A" и символ 'A'

В программировании есть шутка: «две кавычки решают судьбу проекта». И, к сожалению, это почти правда. В C++ есть строковые литералы в двойных кавычках "..." и символьные литералы в одинарных '...'. Разница принципиальная: строка — это последовательность символов, а символ — это ровно один символ.

Если вам нужно хранить имя "Ada", это строка. Если вам нужен один символ, например первая буква имени 'A', это символ. std::string хранит строку, а тип для одного символа мы пока воспринимаем просто как «один знак» (формально это char, но об этом позднее).

Сравните:

#include <iostream>
#include <string>

int main() {
    std::string word = "Cat";                   // строка текста
    char firstLetter = 'C';                     // один символ

    std::cout << word << '\n';        // Cat
    std::cout << firstLetter << '\n'; // C
}

На вид похоже, но смысл другой: word может быть любой длины, а firstLetter — строго один символ.

3. Конкатенация: + и +=

Переходим к очень «человеческой» операции: собрать из кусочков одну красивую фразу. В строках это называется конкатенацией. Представьте, что строка — это конструктор LEGO, только вместо кубиков слова и пробелы. А вы собираете предложение, которое потом покажете пользователю.

Есть два основных способа склеивания:

  • a + b создаёт новую строку (как будто вы взяли два листочка и сделали третий, где написано всё вместе).
  • a += b дописывает в существующую строку (как будто вы продолжили писать на том же листочке).

Начнём с +:

#include <iostream>
#include <string>

int main() {
    std::string first = "Ada";
    std::string last = "Lovelace";

    std::string full = first + " " + last;
    std::cout << full << '\n'; // Ada Lovelace
}

Обратите внимание на " ". Пробел — это тоже символ, а часто и смысл. Если забыть пробел, получится AdaLovelace, что звучит как имя класса, но не как имя человека.

Теперь вариант с += — он удобен, когда вы строите строку постепенно:

#include <iostream>
#include <string>

int main() {
    std::string badge = "Name: ";
    badge += "Ada";
    badge += " ";
    badge += "Lovelace";

    std::cout << badge << '\n'; // Name: Ada Lovelace
}

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

Небольшая важная ремарка: строку и число нельзя просто так «плюсовать» как строки. Например, "Age: " + 10 — так не работает, потому что это разные типы. Мы пока не будем углубляться в преобразования; просто фиксируем: строки склеиваются со строками.

4. Длина строки: size()

Когда вы держите в руках строку, часто хочется понимать, сколько в ней символов. Для этого у std::string есть метод size() (иногда также встречается length(), но сегодня достаточно size()). Это как спидометр, который показывает «сколько символов сейчас в строке».

Посмотрим в деле:

#include <iostream>
#include <string>

int main() {
    std::string city = "Boston";
    std::cout << city.size() << '\n'; // 6
}

Важно привыкнуть к мысли: size() — это первое, что вы вспоминаете перед тем, как полезть внутрь. Потому что индексация без понимания длины — это как идти по лестнице в темноте, считая, что ступеньки бесконечные. Спойлер: ступеньки конечные, а колено одно.

Ещё один пример, где длина помогает увидеть, что пробел — тоже символ:

#include <iostream>
#include <string>

int main() {
    std::string s = "Hi Bob";
    std::cout << s.size() << '\n'; // 6  (H i _ B o b)
}

5. Индексирование: s[i]

Как вы уже выяснили - стока это набор символов. А раз это набор символов, то можно получить отдельные символы из стоки по их номеру.

Важно!

В программировании почти вся нумерация идет с нуля. Нумерация с нуля означает: первый символ — это s[0], второй — s[1], и так далее.

Представим строку как ящик с ячейками:

flowchart LR
    A["s = 'c a t'"] --> B["индексы: 0 1 2"]

Посмотрим на код:

#include <iostream>
#include <string>

int main() {
    std::string animal = "cat";

    std::cout << animal[0] << '\n'; // c
    std::cout << animal[1] << '\n'; // a
    std::cout << animal[2] << '\n'; // t
}

Про границы

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

Индекс должен быть в диапазоне от 0 до s.size() - 1. Если строка длины 3, допустимые индексы — 0, 1, 2. Если попытаться взять animal[3], вы выходите за границы строки и программа падает.

В C++ это опасно тем, что программа может вести себя непредсказуемо: иногда «как будто работает», иногда печатает странные символы, иногда падает. И это как раз тот случай, когда «иногда работает» хуже, чем «сразу падает», потому что баг прячется и ждёт подходящего момента.

Можно ли менять символы в строке?

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

#include <iostream>
#include <string>

int main() {
    std::string word = "bat";
    word[0] = 'c';

    std::cout << word << '\n'; // cat
}

Обратите внимание: справа стоит 'c' в одинарных кавычках, потому что мы присваиваем один символ, а не строку "c".

6. Первое знакомство с методами

Вы могли заметить странную запись:

city.size()

Почему мы не пишем просто size(city)? Потому что size() — это метод.

Метод — это функция, которая принадлежит конкретному типу или объекту. В нашем случае std::string — это тип, а city — объект этого типа. И у строк есть свои «встроенные умения»: узнавать длину, дописывать текст, получать символ по индексу и многое другое.

Когда функция принадлежит объекту, к ней обращаются через точку:

объект.метод()

Точка читается почти по-человечески: «Возьми объект city и вызови у него метод size()».

То есть строка как бы «сама знает», как определить свою длину. Это и есть идея методов: поведение связано с данными.

Посмотрите на уже знакомые примеры:

std::string full = first + " " + last;

std::cout << full.size() << '\n';
std::cout << full[0] << '\n';

full.size() — строка сама сообщает свою длину. full[0] — мы обращаемся к её внутреннему символу.

Позже вы увидите, что почти все сложные типы в C++ имеют свои методы. Например, у std::vector есть push_back(), у std::string есть substr(), у потоков есть clear(). Это один из ключевых принципов языка: данные и связанные с ними операции объединены.

Важно привыкнуть к этой записи. Всё, что выглядит как:

что_то.что_то()

почти всегда означает вызов метода объекта.

Именно поэтому мы пишем full.size(), а не просто size(full). Строка сама предоставляет инструменты для работы с собой.

7. Мини-приложение: консольная визитка

Теперь соберём всё в один небольшой цельный фрагмент: сделаем визитку, которая печатает имя, длину полного имени и первую букву. Пока данные возьмём прямо из кода (ввод будет в следующей лекции), чтобы не смешивать новые темы в одну кучу.

В этом примере у нас появится «ощущение приложения»: не просто отдельные операции, а маленький полезный вывод.

#include <iostream>
#include <string>

int main() {
    std::string first = "Ada";
    std::string last = "Lovelace";

    std::string full = first + " " + last;

    std::cout << "Full name: " << full << '\n';          // Full name: Ada Lovelace
    std::cout << "Length: " << full.size() << '\n';      // Length: 12
    std::cout << "First letter: " << full[0] << '\n';    // First letter: A
}

Здесь спрятано сразу несколько важных привычек.

Во-первых, мы явно добавили пробел между именем и фамилией, потому что компьютер не догадается, что «между словами должно быть место». Во-вторых, мы вывели длину строки: это помогает понять, что пробел тоже считается. В-третьих, мы взяли full[0] и достали первый символ, что даёт нам в будущем возможность делать инициалы или простые сокращения.

Если хочется чуть-чуть «поиграться», можно достать последнюю букву фамилии. Формально последняя буква имеет индекс size() - 1. Мы делаем это только на заведомо непустой строке, чтобы не рисковать выходом за границы:

#include <iostream>
#include <string>

int main() {
    std::string last = "Lovelace";
    char lastChar = last[last.size() - 1];

    std::cout << lastChar << '\n'; // e
}

Да, выражение выглядит слегка «математически», но логика простая: если длина 8, индексы идут 0…7, значит последний — 7, то есть size() - 1.

Памятка по операциям со строками

Чтобы не держать всё в голове одновременно, полезно иметь маленькую «карту местности». Ниже — краткая таблица с тем, что мы сегодня использовали (без погружения в более продвинутые методы строк, они будут позже).

Действие Пример Что происходит
Создать строку
std::string s = "Hi";
В s хранится текст
Склеить строки
a + b
Создаётся новая строка
Дописать к строке
s += part;
s становится длиннее
Длина строки
s.size()
Получаем количество символов
Символ по индексу
s[i]
Получаем один символ (или можем заменить)

Эта таблица — ваш «минимальный набор», который пригодится почти в любой консольной задаче: от печати приветствия до первичной обработки текста.

8. Типичные ошибки при работе со std::string

Ошибка №1: забыли #include <string>.
Иногда код «вроде бы» компилируется из‑за косвенных подключений, а иногда внезапно перестаёт. Правильная привычка простая: используете std::string — подключайте <string>. Это не прихоть, а реальная дисциплина: даже в примерах и документах встречаются правки, где добавляют недостающий include, потому что иначе пример некорректный.

Ошибка №2: перепутали "A" и 'A'.
Когда вы пишете word[0] = "b";, компилятор вам справедливо скажет: «эй, слева один символ, а справа строка». Для одного символа используйте одинарные кавычки: 'b'. Для текста — двойные: "b".

Ошибка №3: забыли про пробел при конкатенации.
Классика: first + last даёт “AdaLovelace”, а вы потом долго смотрите на результат и думаете, что программа сломалась. На самом деле она слишком буквальная: не попросили пробел — не добавила. Добавляйте " " явно.

Ошибка №4: индекс вышел за границы строки.
s[100] у строки "Hi" — это не «пустота», не null и не «просто ничего». Это выход за границы, и поведение программы становится непредсказуемым. До появления if мы просто не делаем такие индексы «наугад» и всегда опираемся на size().

Ошибка №5: ожидали, что size() — это «количество букв в любом языке».
На старте курса мы обычно работаем с простыми латинскими примерами, где один символ примерно равен одной «букве». В реальных текстах (особенно с кириллицей в UTF‑8) это может быть сложнее, но пока наша задача — освоить базовую механику строк, а не войну с кодировками.

1
Задача
C++ SELF, 2 уровень, 2 лекция
Недоступна
Афиша кино
Афиша кино
1
Задача
C++ SELF, 2 уровень, 2 лекция
Недоступна
Мини визитка
Мини визитка
1
Задача
C++ SELF, 2 уровень, 2 лекция
Недоступна
Первый и последний
Первый и последний
1
Задача
C++ SELF, 2 уровень, 2 лекция
Недоступна
Исправить логин
Исправить логин
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Flok Уровень 13
29 марта 2026
5. Индексирование: s[i] Как вы уже выяснили - стока это набор символов. А раз это набор символов, то можно получить отдельные символы из стоки по их номеру.