Ваша первая программа на языке C++, вероятно, была:
1 2 3 4 5 6 7 |
#include <iostream> int main() { std::cout << "Hello, world!" << std::endl; return 0; } |
Не так ли? Но что такое «Hello, world!»? «Hello, world!» — это последовательность символов, называемых строкой или string. В C++ мы используем строки для представления текста (имен, адресов, слов и предложений). Строковые литералы (такие как «Hello, world!») помещаются между двойными кавычками.
Поскольку их часто используют в программах, большинство современных языков программирования имеют встроенный тип данных string. В C++ есть свой, но не как часть основного языка, а как часть стандартной библиотеки.
std::string
Чтобы иметь возможность использовать строки в C++, сначала нужно подключить заголовочный файл <string>. Как только это будет сделано, мы сможем определять переменные типа std::string.
1 2 3 |
#include <string> std::string name; |
Как и с обычными переменными, вы можете инициализировать или присваивать им значения:
1 2 |
std::string name("Sasha"); // инициализируем переменную name строковым литералом "Sasha" name = "Masha"; // присваиваем переменной myName строковый литерал "Masha" |
Строки также могут содержать числа:
1 |
std::string myID("34"); // "34" здесь - это не целое число 34! |
Стоит отметить, что числа string обрабатываются как текст, а не как числа, и, следовательно, ими нельзя манипулировать как с обычными числами (например, вы не сможете их умножать). C++ автоматически не преобразовывает их в значения типов int или float.
Ввод/вывод строк
Строки выводить можно с помощью std::cout:
1 2 3 4 5 6 7 8 9 10 |
#include <string> #include <iostream> int main() { std::string name("Sasha"); std::cout << "My name is: " << name; return 0; } |
Результат:
My name is: Sasha
А вот с std::cin уже немного по-другому. Рассмотрим следующий пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <string> #include <iostream> int main() { std::cout << "Enter your full name: "; std::string myName; std::cin >> myName; // это будет работать не так, как ожидается, поскольку извлечение данных в потоке std::cin останавливается на первом пробеле std::cout << "Enter your age: "; std::string myAge; std::cin >> myAge; std::cout << "Your name is " << myName << " and your age is " << myAge; } |
Результаты пробного запуска этой программы:
Enter your full name: Sasha Mak
Enter your age: Your name is Sasha and your age is Mak
Хм, это неправильно! Что же случилось? Оказывается, оператор >> извлечения строки из cin возвращает символы только до первого пробела. Любые другие символы остаются внутри cin, ожидая следующего извлечения.
Поэтому, когда мы использовали оператор >> для извлечения строки в переменную myName, только «Sasha» был извлечен, «Mak» осталось внутри std::cin, ожидая следующего извлечения. Когда мы использовали оператор >> снова, чтобы извлечь строку в переменную myAge, мы получили «Mak» вместо «25». Если бы мы сделали третье извлечение, мы бы получили «25».
Использование std::getline() для ввода текста
Чтобы извлечь полную строку ввода — лучше использовать функцию std::getline(). Она принимает два параметра: первый – std::cin, второй — переменная string.
Вот та же программа, что выше, но уже с использованием std::getline():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <string> #include <iostream> int main() { std::cout << "Enter your full name: "; std::string myName; std::getline(std::cin, myName); // считываем целую строку текста в переменную myName std::cout << "Enter your age: "; std::string myAge; std::getline(std::cin, myAge); // считываем целую строку текста в переменную myAge std::cout << "Your name is " << myName << " and your age is " << myAge; } |
Теперь программа работает как надо:
Enter your full name: Sasha Mak
Enter your age: 25
Your name is Sasha Mak and your age is 25
Использование std::cin и std::getline()
Чтение вводов как с std::cin, так и с std::getline иногда может создавать неожиданные результаты. Рассмотрим следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <string> #include <iostream> int main() { std::cout << "Pick 1 or 2: "; int choice; std::cin >> choice; std::cout << "Now enter your name: "; std::string myName; std::getline(std::cin, myName); std::cout << "Hello, " << myName << ", you picked " << choice << '\n'; return 0; } |
Возможно, вы удивитесь, но когда запустите эту программу и она попросит вас ввести ваше имя, она не будет ожидать вашего ввода, а сразу выведет результат (просто пробел вместо вашего имени)! Пробный запуск:
Pick 1 or 2: 2
Now enter your name: Hello, , you picked 2
Почему так? Оказывается, когда вы вводите числовое значение с помощью cin, cin не только захватывает числовое значение, но и символ новой строки. Так что, когда мы ввели 2, cin фактически получил «2\n». Затем он извлек значение 2 в переменную, оставляя \n (символ новой строки) во входном потоке. Затем, когда std::getline будет считывать данные для myName, он увидит в потоке «\n», и подумает, что мы, должно быть, ввели просто пустую строку! А это определенно не то, что должно быть на самом деле.
Хорошее эмпирическое правило состоит в том, что после считывания числового значения с std::cin удалите символ новой строки из потока. Это можно осуществить так:
1 |
std::cin.ignore(32767, '\n'); // игнорируем до 32767 символов до тех пор, пока \n не будет удален из потока |
Если мы вставим эту строку непосредственно после считывания переменной, символ новой строки будет удален из потока, и программа будет работать как надо!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
int main() { std::cout << "Pick 1 or 2: "; int choice; std::cin >> choice; std::cin.ignore(32767, '\n'); // удаляем символ новой строки из потока std::cout << "Now enter your name: "; std::string myName; std::getline(std::cin, myName); std::cout << "Hello, " << myName << ", you picked " << choice << '\n'; return 0; } |
Правило: Если вы вводите числовые значения, используя std::cin, не забывайте удалять символ новой строки с помощью std::cin.ignore().
Добавление строк
Вы можете использовать оператор +, чтобы объединить две строки, или оператор +=, чтобы добавить одну строку к другой.
Вот пример того и другого, также показано, что произойдет, если вы попытаетесь использовать оператор +, чтобы добавить две числовые строки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <string> #include <iostream> int main() { std::string x("44"); std::string y("12"); std::cout << x + y << "\n"; // x и y мы объединяем, не добавляем x += " cats"; std::cout << x; return 0; } |
Результат:
4412
44 cats
Обратите внимание, оператор + соединил строки «44» и «12» в «4412». Он не добавлял их как числа.
Длина строк
Если мы хотим узнать длину строки, мы можем сделать на это запрос. Синтаксис немного отличается от того, что вы видели ранее, но он довольно прост:
1 2 3 4 5 6 7 8 9 |
#include <string> #include <iostream> int main() { std::string myName("Sasha"); std::cout << myName << " has " << myName.length() << " characters\n"; return 0; } |
Результат:
Sasha has 5 characters
Обратите внимание, вместо запроса длины строки как length(myName)
, мы пишем myName.length()
.
Функция запроса длины строки не является обычной функцией, как те, которые мы использовали до этого момента — это особый тип функции std::string, который называется функцией-членом. Мы рассмотрим этот тип функций и то, как создавать собственные функции-члены, более подробно в следующих уроках.
Тест
Напишите программу, которая спрашивает у пользователя его имя-фамилию и возраст. В результате также укажите пользователю, сколько лет он прожил с каждой буквы своего имя-фамилии (чтобы было проще, пробелы тоже считаются буквами).
Например:
Enter your full name: John Doe
Enter your age: 46
You've lived 5.75 years for each letter in your name.
Уточнение: То есть, если возраст 46, а имя «John Doe» (8 букв вместе с пробелом), то 46 делим на 8. Получаем 5.75.
Ответ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <string> #include <iostream> int main() { std::cout << "Enter your full name: "; std::string myName; std::getline(std::cin, myName); // считываем целую строку текста в переменную myName std::cout << "Enter your age: "; int myAge; // переменная myAge должна быть типа int, не string, чтобы мы могли проводить с ней арифметические операции std::cin >> myAge; int letters = myName.length(); // узнаем количество букв в переменной myName (учитывая пробелы) double agePerLetter = static_cast<double>(myAge) / letters; // используем static_cast, чтобы изменить тип переменной myAge в double, дабы сохранить дробную часть целочисленного деления std::cout << "You've lived " << agePerLetter << " years for each letter in your name.\n"; return 0; } |
у меня так получилось:
У меня как-то размазано получилось по сравнению с ответом )))
Подскажите, насколько код написан красиво, вроде старался следовать всем рекомендациям.
Что-то у меня не получается. Ввожу имя "Саша", возраст — "12" и получаю "1,5" на выходе, а должен же 4. Что не так? Вот код:
Скопировал программу, у меня всё нормально выдаёт, но выдать он должен 3, а не 4 (12 / 4 = 3)
А почему сразу myAge не присвоить double, и обойтись без промежуточного agePerLetter, а деление выполнить в строке вывода?
Здравствуйте, подскажите, пожалуйста, почему в приведенной функции выскакивает предупреждение? Я так понимаю linker не доволен… но программа компилируется и работает правильно вроде. Заранее благодарна.
Функция "std::getline" получает от пользователя не цифру, а строку, так что число которое ты введёшь, будет просто строкой, а не числом (звучит странно), при этом ты пытаешься в тип данных Int "впихнуть" строчку. Проще говоря, это тоже самое, что написать:
Надеюсь, я объяснил понятно 🙂
А нет, я пересмотрел программу, и не знаю в чём проблема 😀
было бы неплохо увидеть само предупреждение
Добрый вечер! Спасибо за feedback.
Ниже код и предупреждение:
Файл io.h
Файл io.cpp
Файл main.cpp
Предупреждение в файле io.cpp в строке int nameLength = name.length();
Implicit conversion loses integer precision: 'std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::s
Названия файлов просто лень переименовывать )))
Спасибо!
Метод length() возвращает тип unsigned int, который вы присваиваете переменной signed int. Из-за этого происходит неявное преобразование с возможностью потери точности. Это можно решить с помощью изначального типа переменной unsigned int, но я бы просто забил, ведь чтобы произошло переполнение, пользователь должен ввести имя длинною более чем в 2 147 483 647 символов, а это…хммм, как бы немного многовато
Get Leevz, почему-то не могу ответить на ваш комментарий, поэтому отвечаю на свой )) Спасибо вам большое за разъяснения, сама бы до этого не дошла!
Юрий, доброго дня. Подскажите, в чём разница в данных записях, если работают обе, переводя число в double и мы получаем на выходе число с плавающей точкой.
вместо
можно ли обходиться в принципе без static_cast?
Спасибо.
Привет. Ответ на ваш вопрос находится в уроке 56.
А обязательно переводить вручную? Я просто дал переменной возраста тип float. Компилятор же сам преобразовывает типы
Перечитал урок 7.
Проблема 1
Как использовать русский язык в консоли C++?
Слово в слово повторено как в программе выше и где сказано что всё работает.
У меня в CodeBlocks не работает. Возможно в студии будет работать , не проверял.
Остается в уроке 7 прочитать совет в самом низу: Во-первых, спросите Google…
Верно, если Google не поможет, спросите на StackOverflow. Код рабочий, если у вас не работает, значит у вас уже специфическая проблема: возможно кодировка в Code:Blocks у вас не та, что нужно. Возможно, у вас что-то подключено (плагин, расширение или что-либо другое), что блокирует корректное выполнение setlocale.
Ясно, спасибо. Подключена русификация интерфейса и все. Пока не искал решения проблемы, т.к. это не сильно влияет на изучение.
Огромное спасибо за такой нужный труд по переводу и поддержанию сайта с этим учебным курсом. Из всего что я находил ,это самое лучшее. Спасибо!!!
Пожалуйста 🙂
Попробуйте отключить русификацию интерфейса и посмотрите какая у вас кодировка стоит — сбросьте всё до значений по умолчанию. И если уже никак, то вы знаете, где искать.
Скажите, пожалуйста, что я не так сделал!
Ваш код рабочий. Результаты совпадают.
Что не так:
1. У вас функция im9_famili9 выполняет сразу два задания: получает строку и высчитывает её длину. (Функция должна выполнять одно задание)
2. Функции result нужно было присвоить тип void и ничего не возвращать, а сразу выводить результат в консоль. А то у вас result выводит результат и возвращает его еще в main() — зачем и почему? В main вы с переменной z ничего не делаете, её объявление вообще не нужно.
Всё остальное гуд.
Точно..
Спасибо больше!)
Отличные уроки!!!
Догоняю программу в ВУЗе с помощью этого сайта!
Если честно, то я тоже свою программу из универа догнал и перегнал именно по этим урокам 🙂
Спасибо!!!
Пожалуйста 🙂
Уважаемый автор, почему при выводе в консоль значение переменной myName, не поддерживается кириллица!
Нужно подключить Windows.h (заголовочный файл) и прописать строчки:
Вот всё работает:
Почему-то в CodeBlocks 17.12 выводит этим способом кракозябры как на ввод ,так и на вывод. Если использовать setlocale(LC_ALL, "rus"); или setlocale(LC_ALL, ""); вывод идет на русском , а на ввод кракозябры ,если использовать
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
то даже при подключенном setlocale(LC_ALL, "rus"); все равно кракозябры.
Ответ на ваш вопрос ищите в Уроке 7. Самые распространенные проблемы и их решения в C++.
Разве setlocale(LC_ALL, "rus") уже не помогает?