Рассмотрим более сложный пример и используем серийный оператор for, а также функцию ispunct() для подсчета количества знаков пунктуации в строке:
string s("Hello World!!!");
// punct_cnt имеет тот же тип, что и у возвращаемого значения
// функции s.size(); см. p. 2.5.3
decltype(s.size()) punct_cnt = 0;
// подсчитать количество знаков пунктуации в строке s
for (auto с : s) // для каждого символа в строке s
if (ispunct(c)) // если символ знак пунктуации
++punct_cnt; // увеличить счетчик пунктуаций
cout << punct_cnt
<< " punctuation characters in " << s << endl;
Вывод этой программы таков:
3 punctuation characters in Hello World!!!
Здесь для объявления счетчика punct_cnt используется спецификатор decltype (см. раздел 2.5.3). Его тип совпадает с типом возвращаемого значения функции s.size(), которым является тип string::size_type. Для обработки каждого символа в строке используем серийный оператор for. На сей раз проверяется, является ли каждый символ знаком пунктуации. Если да, то используем оператор инкремента (см. раздел 1.4.1) для добавления единицы к счетчику. Когда серийный оператор for завершает работу, отображается результат.
for для изменения символов в строкеЕсли необходимо изменить значение символов в строке, переменную цикла следует определить как ссылочный тип (см. раздел 2.3.1). Помните, что ссылка — это только другое имя для данного объекта. При использовании ссылки в качестве управляющей переменной она будет по очереди связана с каждым элементом последовательности. Используя ссылку, можно изменить символ, с которым она связана.
Предположим, что вместо подсчета знаков пунктуации необходимо преобразовать все буквы строки в верхний регистр. Для этого можно использовать библиотечную функцию toupper(), которая возвращает полученный символ в верхнем регистре. Для преобразования всей строки необходимо вызвать функцию toupper() для каждого символа и записать результат в тот же символ:
string s("Hello World!!!");
// преобразовать s в верхний регистр
for (auto &с : s) // для каждого символа в строке s
// (примечание: с - ссылка)
с = toupper(с); // с - ссылка, поэтому присвоение изменяет
// символ в строке s
cout << s << endl;
Вывод этого кода таков:
HELLO WORLD!!!
На каждой итерации переменная с ссылается на следующий символ строки s. При присвоении значения переменной с изменяется соответствующий символ в строке s.
с = toupper(с); // с - ссылка, поэтому присвоение изменяет
// символ в строке s
Таким образом, данное выражение изменяет значение символа, с которым связана переменная с. По завершении этого цикла все символы в строке str будут в верхнем регистре.
Серийный оператор for работает хорошо, когда необходимо обработать каждый символ. Но иногда необходим доступ только к одному символу или к некоторому количеству символов на основании некоего условия. Например, можно преобразовать в верхний регистр только первый символ строки или только первое слово в строке.
Существуют два способа доступа к отдельным символам в строке: можно использовать индексирование или итератор. Более подробная информация об итераторах приведена в разделе 3.4 и в главе 9.
Оператор индексирования (оператор []) получает значение типа string::size_type (раздел 3.2.2), обозначающее позицию символа, к которому необходим доступ. Оператор возвращает ссылку на символ в указанной позиции.