Проблема с cin при вводе пробелов, используя класс string

У меня есть следующий код:

main.cpp

#include <iostream>
#include <string>

using namespace std;

string name;
string age;

int main() {
    cout <<"Name: ";
    cin >> name;
    cout << endl;
    cout <<"Age: ";
    cin >> age;
    cout << endl;
    cout << "Your name is " << name << ", and you are " << age << " years old."  << endl;
    cout << "Press enter to close this application" << endl;
    getchar();
    return 0;
}

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

Screenshot of console

Я также заметил еще одну ошибку, с которой у меня никогда не было проблем с Java. Я не могу понять, как предотвратить его немедленное закрытие при завершении обработки. Я слышал, что вы можете использовать "system. (" Pause "), но мне также сказали не использовать его. Я действительно смущен тем, что использовать. Я слышал, чтобы использовать getchar();, но он ничего не делает.

Любая помощь будет принята с благодарностью, поскольку я начинаю начинать, когда дело доходит до С++.

Ответ 1

Вот что происходит с входным буфером при запуске вашей программы:

std::cin >> name;

Вы ждете ввода. Когда вы вводите "Ryan Cleary" и нажимаете enter, буфер ввода содержит:

Ryan Cleary\n

Теперь ваш cin читает ввод как обычно, останавливаясь в пробеле, оставляя ваш буфер следующим образом:

 Cleary\n

Обратите внимание на начальное пространство, так как оно останавливается после прочтения Ryan. Ваша первая переменная теперь содержит Ryan. Если, однако, вы хотите получить полное имя, используйте std::getline. Он будет читать до новой строки, а не только пробелов. В любом случае, продолжая:

std::cin >> age;

Теперь вы получаете еще один вход. Однако там что-то есть. Он пропускает пробелы, пока не начнет чтение, оставив буфер только:

\n

Вторая переменная получает текст Cleary. Обратите внимание на новую строку в буфере, которая возвращает меня ко второй части. Замена system ("pause"); таким образом, который всегда работает, сложна. Лучше всего, как правило, жить с решением, отличным от совершенства, или, как мне нравится, тем, что не гарантируется, что он точно говорит:

std::cin.get(); //this consumes the left over newline and exits without waiting

Хорошо, поэтому cin.get() не работает. Как насчет этого:

std::cin.get(); //consume left over newline
std::cin.get(); //wait

Это работает отлично, но что, если вы скопируете-вставьте его где-нибудь, где новая строка не останется? Вам нужно дважды нажать Enter!

Решение состоит в том, чтобы очистить новую строку (и все остальное), а затем подождать. Это цель cin.sync(). Однако, как видно из раздела примечаний, не гарантируется очистка буфера, как он говорит, поэтому, если ваш компилятор не захочет, его нельзя использовать. Для меня, тем не менее, он делает именно это, оставляя решение:

std::cin.sync(); //clear buffer
std::cin.get(); //wait

Самое плохое в system("pause"); заключается в том, что вы понятия не имеете, какую программу он будет запускать на другом компьютере. Они могли бы изменить pause.exe или поместить тот, который был найден первым, и вы не знаете. Это может потенциально разрушить их компьютер из-за того, что это возможно любая программа.

Ответ 2

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

Хорошо, плохие советы, как указывали некоторые люди. Вы можете использовать std:: getline для чтения целой строки. Опять же, разделитель является новой линией, если только не сообщается. Для чтения из cin вы можете передать его как первый параметр (и строку как вторую).

std::string str;
std::getline(cin, str); // to read until the end of line

std::getline(cin, str, ' '); // to read until a space character, for instance

(конечно, вы можете опустить часть std:: из строк, так как вы уже сообщили компилятору, что используете пространство имен std)