С++ getline не пуст, когда ввод не вводится

Я новичок в С++ и все еще пытаюсь понять, как работают потоки ввода/вывода.

В настоящее время я пытаюсь написать функцию, чтобы убедиться, что пользователь вводит int, и сообщить им, является ли ввод пустым или недействительным int.

Я использую getline и пробовал использовать cin.clear и cin.ignore, но я не могу заставить это работать и понятия не имею, где я ошибаюсь.

Это работает, если я ввожу букву, однако, если я просто нажимаю ввод без ввода, он не говорит, что ввод не обнаружен.

void testStuff()
{
    string number;

    ws(cin);//skips Whitespaces

    if (getline(cin, number) && number.end() !=
        find_if_not(number.begin(), number.end(), &isdigit))
    {
        if (number.empty())
        {
            cout << "No input detected" << endl;
            testStuff();
        }
        cout << "Please input a Valid number" << endl;
        testStuff();
    }
}

person Michael Grinnell    schedule 08.11.2017    source источник
comment
Если строка пуста, единственное, что может вернуть find_if_not, это number.end(). number.end() == number.end() и тело не введено.   -  person user4581301    schedule 08.11.2017
comment
Предполагая, что ваш ws работает как указано, вы не сможете ввести пустой ввод. Если вы просто нажмете клавишу enter, это будет прочитано как символ новой строки, который классифицируется как пробел (т. е. isspace('\n') == true). Для вызова getline вы должны ввести что-то, кроме пробелов, поэтому то, что вы читаете с помощью getline, не может быть пустым.   -  person Jerry Coffin    schedule 08.11.2017
comment
@JerryCoffin да, но ws предшествует вызову getline   -  person Michael Grinnell    schedule 08.11.2017
comment
@user4581301 user4581301 Я понимаю, что вы говорите, я должен сначала проверить, пусто ли оно   -  person Michael Grinnell    schedule 08.11.2017
comment
@MichaelGrinnell: Именно так, чтобы выполнение перешло к вызову getline, пользователь должен ввести что-то, что не является пробелом. Когда вызывается getline, этот непробельный символ должен находиться во входном буфере, поэтому то, что он читает, не может быть пустым.   -  person Jerry Coffin    schedule 08.11.2017


Ответы (2)


Предполагая, что ваш ws работает как указано (пропускает пробелы во входных данных), к тому времени, когда вы вызываете getline, должно быть введено что-то кроме пробелов. Таким образом, когда вызывается getline, этот непробельный символ должен ожидать во входном буфере, а getline должен возвращать непустую последовательность символов (т. ).

Например, давайте напишем наш собственный ws, который показывает, какие символы он пропускает:

void ws(std::istream &is) {
    while (std::isspace(is.peek())) {
        char ch;
        is.get(ch);
        std::cout << "Read: " << (int)ch << '\n';
    }
}

Теперь, когда мы вызываем testStuff() и просто нажимаем enter, мы получаем Read: 10 в качестве нашего вывода, т. е. ws прочитал и пропустил новую строку, которую мы ввели.

Итак, чтобы перейти к вызову getline, пользователь должен ввести что-то кроме пробела, а символ новой строки — это пробел. Итак, но когда getline вообще вызывается, мы знаем, что во входном буфере есть какой-то непробельный символ, поэтому, когда вызывается getline, он должен давать непустой результат.

person Jerry Coffin    schedule 08.11.2017
comment
Ладно, да, мне понадобилась минута, чтобы обернуться. В основном избавьтесь от ws, сначала проверьте, пуст ли ввод, а затем проверьте, является ли это цифрой. спасибо :) - person Michael Grinnell; 08.11.2017

Я предположил, что все функции, реализацию которых я не знаю, написаны правильно. Тогда у меня есть такой код (упрощенный):

#include <iostream>
#include <string>
using namespace std;

int main() {
    string number;
    if (getline(cin, number))
    {
        if (number.empty())
        {
            cout << "No input detected" << endl;
            main();
        }
        cout << "Please input a Valid number" << endl;
        main();
    }
}

Я не знаю реализации find_if_not(number.begin(), number.end(), &isdigit), поэтому пропустил. Я разместил исходный код на Ideone.com, вы можете просмотреть его ЗДЕСЬ. После прохождения "просто введите" программа ведет себя корректно. Значит, одна из реализаций функций, которую вы нам не показали, работает некорректно. Чтобы помочь вам, нам нужен полный исходный код (если нет, только необходимые части). Кроме того, вам следует пропустить «использование пространства имен std;». Думаю, number.end() != find_if_not(number.begin(), number.end(), &isdigit)) реализовано неправильно. Вы должны подумать о том, что кто-то сказал вам в комментариях: «Если строка пуста, единственное, что может вернуть find_if_not, это number.end(). number.end() == number.end(), а тело не введено».

person Kamila Szewczyk    schedule 08.11.2017
comment
Вызов main из программы — это плохо. - person user4581301; 08.11.2017
comment
Конечно есть, но это быстрый и грязный пример. Я не хочу делать 60-строчную программу только для того, чтобы она работала, а такая программа ведет себя как надо. Я не думаю, что ОП будет использовать мой код... - person Kamila Szewczyk; 08.11.2017
comment
@KrzysztofSzewczyk find_if_not принимает первую и последнюю позицию и возвращает итератор к первому вхождению определенного условия. Итак, isdigit - это условие, поэтому, если оно возвращает последний элемент, это означает, что целых чисел нет. - person Michael Grinnell; 08.11.2017