Урок 57. Введение в std::string

  Юрий Ворон  | 

    | 

  Обновлено 29 Апр 2017  | 

 17903

 ǀ   27 

Ваша первая программа на языке C++, вероятно, была:

Не так ли? Но что такое «Hello, world!»? «Hello, world!» — это последовательность символов, называемых строкой или string. В C++ мы используем строки для представления текста (имен, адресов, слов и предложений). Строковые литералы (такие как «Hello, world!») помещаются между двойными кавычками.

Поскольку их часто используют в программах, большинство современных языков программирования имеют встроенный тип данных string. В C++ есть свой, но не как часть основного языка, а как часть стандартной библиотеки.

std::string

Чтобы иметь возможность использовать строки в C++, сначала нужно подключить заголовочный файл <string>. Как только это будет сделано, мы сможем определять переменные типа std::string.

Как и с обычными переменными, вы можете инициализировать или присваивать им значения:

Строки также могут содержать числа:

Стоит отметить, что числа string обрабатываются как текст, а не как числа, и, следовательно, ими нельзя манипулировать как с обычными числами (например, вы не сможете их умножать). C++ автоматически не преобразовывает их в значения типов int или float.

Ввод/вывод строк

Строки выводить можно с помощью std::cout:

Результат:

My name is: Sasha

А вот с std::cin уже немного по-другому. Рассмотрим следующий пример:

Результаты пробного запуска этой программы:

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():

Теперь программа работает как надо:

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 иногда может создавать неожиданные результаты. Рассмотрим следующее:

Возможно, вы удивитесь, но когда запустите эту программу и она попросит вас ввести ваше имя, она не будет ожидать вашего ввода, а сразу выведет результат (просто пробел вместо вашего имени)! Пробный запуск:

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 удалите символ новой строки из потока. Это можно осуществить так:

Если мы вставим эту строку непосредственно после считывания переменной, символ новой строки будет удален из потока, и программа будет работать как надо!

Правило: Если вы вводите числовые значения, используя std::cin, не забывайте удалять символ новой строки с помощью std::cin.ignore().

Добавление строк

Вы можете использовать оператор +, чтобы объединить две строки, или оператор +=, чтобы добавить одну строку к другой.

Вот пример того и другого, также показано, что произойдет, если вы попытаетесь использовать оператор +, чтобы добавить две числовые строки:

Результат:

4412
44 cats

Обратите внимание, оператор + соединил строки «44» и «12» в «4412». Он не добавлял их как числа.

Длина строк

Если мы хотим узнать длину строки, мы можем сделать на это запрос. Синтаксис немного отличается от того, что вы видели ранее, но он довольно прост:

Результат:

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 (63 оценок, среднее: 4,92 из 5)
Загрузка...

Комментариев: 27

  1. Giveyn:

    А почему сразу myAge не присвоить double, и обойтись без промежуточного agePerLetter, а деление выполнить в строке вывода?

  2. Ярослав:

  3. Katerina:

    Здравствуйте, подскажите, пожалуйста, почему в приведенной функции выскакивает предупреждение? Я так понимаю linker не доволен… но программа компилируется и работает правильно вроде. Заранее благодарна.

    1. Георгий:

      Функция "std::getline" получает от пользователя не цифру, а строку, так что число которое ты введёшь, будет просто строкой, а не числом (звучит странно), при этом ты пытаешься в тип данных Int "впихнуть" строчку. Проще говоря, это тоже самое, что написать:

      Надеюсь, я объяснил понятно 🙂

      1. Георгий:

        А нет, я пересмотрел программу, и не знаю в чём проблема 😀

    2. Torgu:

      было бы неплохо увидеть само предупреждение

      1. Katerina:

        Добрый вечер! Спасибо за 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

        Названия файлов просто лень переименовывать )))
        Спасибо!

        1. Get Leevz:

          Метод length() возвращает тип unsigned int, который вы присваиваете переменной signed int. Из-за этого происходит неявное преобразование с возможностью потери точности. Это можно решить с помощью изначального типа переменной unsigned int, но я бы просто забил, ведь чтобы произошло переполнение, пользователь должен ввести имя длинною более чем в 2 147 483 647 символов, а это…хммм, как бы немного многовато

        2. Katerina:

          Get Leevz, почему-то не могу ответить на ваш комментарий, поэтому отвечаю на свой )) Спасибо вам большое за разъяснения, сама бы до этого не дошла!

  4. Sergey Groysman:

    Юрий, доброго дня. Подскажите, в чём разница в данных записях, если работают обе, переводя число в double и мы получаем на выходе число с плавающей точкой.

    вместо

    можно ли обходиться в принципе без static_cast?
    Спасибо.

    1. Юрий Юрий:

      Привет. Ответ на ваш вопрос находится в уроке 56.

      1. Torgu:

        А обязательно переводить вручную? Я просто дал переменной возраста тип float. Компилятор же сам преобразовывает типы

  5. Серж:

    Перечитал урок 7.
    Проблема 1
    Как использовать русский язык в консоли C++?
    Слово в слово повторено как в программе выше и где сказано что всё работает.
    У меня в CodeBlocks не работает. Возможно в студии будет работать , не проверял.
    Остается в уроке 7 прочитать совет в самом низу: Во-первых, спросите Google…

    1. Li4ik Li4ik:

      Верно, если Google не поможет, спросите на StackOverflow. Код рабочий, если у вас не работает, значит у вас уже специфическая проблема: возможно кодировка в Code:Blocks у вас не та, что нужно. Возможно, у вас что-то подключено (плагин, расширение или что-либо другое), что блокирует корректное выполнение setlocale.

      1. Серж:

        Ясно, спасибо. Подключена русификация интерфейса и все. Пока не искал решения проблемы, т.к. это не сильно влияет на изучение.
        Огромное спасибо за такой нужный труд по переводу и поддержанию сайта с этим учебным курсом. Из всего что я находил ,это самое лучшее. Спасибо!!!

        1. Li4ik Li4ik:

          Пожалуйста 🙂

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

  6. Максим:

  7. Ka4:

    Скажите, пожалуйста, что я не так сделал!

    1. Li4ik Li4ik:

      Ваш код рабочий. Результаты совпадают.

      Что не так:

      1. У вас функция im9_famili9 выполняет сразу два задания: получает строку и высчитывает её длину. (Функция должна выполнять одно задание)

      2. Функции result нужно было присвоить тип void и ничего не возвращать, а сразу выводить результат в консоль. А то у вас result выводит результат и возвращает его еще в main() — зачем и почему? В main вы с переменной z ничего не делаете, её объявление вообще не нужно.

      Всё остальное гуд.

      1. Ka4:

        Точно..
        Спасибо больше!)
        Отличные уроки!!!
        Догоняю программу в ВУЗе с помощью этого сайта!

        1. Li4ik Li4ik:

          Если честно, то я тоже свою программу из универа догнал и перегнал именно по этим урокам 🙂

  8. Герман:

    Спасибо!!!

    1. Li4ik Li4ik:

      Пожалуйста 🙂

  9. Герман:

    Уважаемый автор, почему при выводе в консоль значение переменной myName, не поддерживается кириллица!

    1. Li4ik Li4ik:

      Нужно подключить Windows.h (заголовочный файл) и прописать строчки:

      Вот всё работает:

      1. Серж:

        Почему-то в CodeBlocks 17.12 выводит этим способом кракозябры как на ввод ,так и на вывод. Если использовать setlocale(LC_ALL, "rus"); или setlocale(LC_ALL, ""); вывод идет на русском , а на ввод кракозябры ,если использовать
        SetConsoleCP(1251);
        SetConsoleOutputCP(1251);
        то даже при подключенном setlocale(LC_ALL, "rus"); все равно кракозябры.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ВОЛШЕБНАЯ ТАБЛЕТКА ПО С++