Практический курс по C/C++: https://stepik.org/course/193691
Я думаю, вы
помните, насколько неудобно было работать со строками в языке Си? Они
описывались одномерным массивом типа char и содержали
набор символов той или иной строки. Например, фразу «Hello, World!»:
char msg[] = "Hello, World!";
В конце каждой
корректной Си-строки должен присутствовать символ ‘\0’, то есть, просто число
0.
Конечно, в С++
мы можем продолжать использовать этот подход для определения набора символов и
работать с ними, как со строками. Но теперь появилась дополнительная
возможность применять объект string, который значительно упрощает
строковые операции на уровне написания программы программистом. Для этого
первым делом необходимо подключить заголовок string в нашей
программе следующим образом:
После этого в
пространстве имен std будет доступен класс string с возможностью
объявления строковых объектов. В самом простом варианте можно записать:
Так как мы не
проходили классы и ООП, то воспринимайте string, как
специальный тип данных для объявления строк. В результате, msg будет
представлять собой пустую строку, то есть, строку, содержащую только одно
значение 0 – маркер конца строки.
В
действительности, класс string базируется на динамическом
массиве символов, в котором хранится текущая строка. Поэтому, нам не
обязательно прописывать максимальную длину строки, это значение будет меняться в
соответствии с длиной хранимой строки. Например, для объекта msg можно вывести
число символов в строке и физический размер динамического массива:
cout << msg.size() << " " << msg.capacity() << endl;
Получим:
0 15
То есть, размер
строки 0, а зарезервировано под строку 15 символов. Если же инициализировать
объект-строку какой-либо строкой:
std::string msg {"Hello, Sergey Balakirev!"};
cout << msg.size() << " " << msg.capacity() << endl;
то увидим числа:
24 24
То есть, размер
динамического массива автоматически был увеличен до 24 – числа символов в
строке.
Саму же строку
можно вывести как обычную переменную с помощью объекта cout следующим
образом:
Или же, получить
константный указатель на строковый массив символов:
const char* data = msg.data();
и, например,
вывести данные с помощью функции printf():
Все это еще раз
показывает, что внутри объекта msg мы имеем все ту же Си-строку в виде
массива символов.
Далее, для
доступа к отдельным символам строки можно по-прежнему использовать оператор [].
Например:
std::string fio {"Sergey Balakirev!"};
std::string fio_new {fio};
fio_new[5] = 'i';
cout << fio_new << endl;
Увидим
измененный символ ‘y’:
Sergei
Balakirev!
Соответственно,
можно прочитать отдельный символ по индексу:
cout << fio_new[0] << endl;
Или, то же самое
можно выполнить с помощью метода at():
fio_new.at(5) = 'i';
cout << fio_new << "\n" << fio_new.at(0) << endl;
Объект-строку
можно перебрать по символам с помощью цикла for. В самом
простом варианте это можно сделать так:
for(const char& ch : fio)
cout << ch << " ";
В более сложном,
использовать итератор для перебора любых последовательностей, определенных в
стандартной библиотеки шаблонов (STL):
for(auto it = msg.cbegin(); it != msg.cend(); ++it)
cout << *it << " ";
Я не буду сейчас
углубляться в эту тему. Привел этот пример для демонстрации многообразия
возможностей языка С++ и библиотеки STL.
Наконец, можно
воспользоваться уже известным вам способом перебора Си-строки:
const char* ptr_str = fio.data();
for(int i = 0; ptr_str[i] != '\0'; ++i)
cout << ptr_str[i] << " ";
Конечно, удобнее
всего использовать первый способ, поэтому чаще всего он и встречается в
программах.
Добавление и объединение строк
Приятной
возможностью объекта-строк является возможность неограниченно (пока хватает
памяти устройства) добавлять новые символы в конец строки. Например, пусть
имеется строка:
std::string msg {"Hello"};
И мы хотим ее
преобразовать в строку «Hello, Sergey!», то есть в
конец дописать недостающий фрагмент. Это легко сделать с помощью метода append() следующим
образом:
msg.append(", Sergey!");
cout << msg << endl;
Также мы можем
объединять строки между собой. Например:
std::string msg {"Hello"};
std::string name {"Sergey"};
msg.append(", ");
msg = msg + name;
cout << msg << endl;
Или, короче:
Или, еще короче:
msg = msg.append(", ") + name;
Все эти варианты
вполне допустимы.
Ввод строк из стандартного входного потока
Наверное,
последний важный момент связан с возможностью ввода строковых данных из
стандартного входного потока stdin. Чаще всего – это ввод строк с
клавиатуры. Так как в программе у нас имеется объект cin, давайте воспользуемся
им и посмотрим, как это будет работать с объектами-строками:
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
int main()
{
std::string msg;
cin >> msg;
cout << msg << endl;
return 0;
}
Если ввести
строку «hello world», то в объекте msg будет только
первый фрагмент «hello». Чтобы прочитать строку целиком (до
символа перевода строки) удобно воспользоваться функцией getline() языка С++.
Например, так:
Теперь, при
вводе «hello world», вся строка
целиком помещается в объект msg.
Третьим аргументом
в этой функции можно указать разделитель, до которого будет читаться введенный
фрагмент. Например, если прописать:
то при вводе:
1, 2; 3, 4
в объект msg будет помещена
строка:
1, 2
Вот базовые
возможности работы с объектами-строками языка С++. Как видите, они несколько
удобнее обычных одномерных массивов символов, используемых в языке Си.
Практический курс по C/C++: https://stepik.org/course/193691