Я пытаюсь создать простую программу, которая принимает двойники и помещает их в вектор. Если значение не является двойным, он проверяет, является ли значение Q, и продолжает выполнение, если оно не равно «Q».

Вот код:

string str = "";

while (str != "Q")
    {
        double n;
        cin >> n;

        if (cin.fail())
        {
            cin.clear();
            cin >> str;

            if (str != "Q")
                cout << "'" << str << "'" << " is invalid input. Please try again!" << endl;
        }

        else
            vec.push_back(n);
    }

Вроде работает отлично. Однако некоторые символы (b, e, c, a и т. Д.) Будут пропущены при попытке вывести str. Например, когда я ввожу because, str выводит use.

Мне также кажется очень странным, что когда я меняю n с double на int, обнаруживаются все символы (Input = because и str выходы because).

Что-то мне не хватает? Разве это не приемлемый способ проверить результат, если это не дубль?

Благодарность!

2
Zack 8 Окт 2014 в 22:58

2 ответа

Лучший ответ

Когда пользователь вводит because, а вы пытаетесь прочитать его как число с cin >> n, он пытается сделать это. Он терпит неудачу в какой-то момент и потребляет все символы до ошибки синтаксического анализа (исключая). Только после использования этих символов он возвращается и отмечает операцию как неудачную (что вы проверяете с помощью cin.fail()). Обратите внимание, что число с плавающей запятой действительно может содержать шестнадцатеричные символы, поскольку они могут быть закодированы в шестнадцатеричной нотации *.

Чтение числа потребляет некоторые шестнадцатеричные цифры, которые являются частью строки, которую вы хотите использовать , если анализ ввода как числа завершился неудачно . (Подробности см. В комментариях под вопросом.)

Простое решение - сначала попытаться прочитать 'q' и, только если это не удается , прочитать число, и если это тоже не удается , пользователь ввел что-то неожиданное. .

Вы можете посмотреть на следующий символ , не употребляя его (так что он все еще используется для анализа числа в случае, если это не 'q', используя cin.peek().

Примере:

if (cin.peek() == 'q') {
    // really consume it, for the case you want to use cin later on again
    cin.get();
    // quit
} else if (cin >> n) {
    // process input n
} else {
    // handle user error; you can still get the whole line from cin
}

*) Две вещи, однако, кажутся странными и могут быть обсуждены в комментариях: во-первых, шестнадцатеричные числа должны начинаться с 0x, поэтому оно должно завершаться ошибкой на самом первом нецифровом / не знаковом символе. Во-вторых, почему тогда int не показывает такое поведение? Целые числа также могут быть закодированы в шестнадцатеричном формате, afaik.

5
leemes 8 Окт 2014 в 19:41

Как предполагалось в комментариях, ваша среда, кажется, интерпретирует шестнадцатеричные цифры как числа с плавающей запятой, что странно. Какую среду вы используете?

Я лично считаю, что правила iostreams, когда они перестают читать, очень не интуитивно понятны. (Например, в GCC ваш цикл интерпретирует «123abc» как «123», за которым следует ошибка.) Если вы хотите прочитать строку текста, а затем обработать ее, как насчет того, чтобы сделать это явно?

while (str != "Q") {
  getline(cin, str);

  // Use stringstream to process one line of text exactly.
  stringstream s(str);
  double n;
  s >> n;

  if (str == "Q") {
    break;
  } else if (s.fail() || !s.eof()) {
    cout << "'" << str << "'" << " is invalid input. Please try again!" << endl;
  } else {
    vec.push_back(n);
  }
}

Boost.Lexical_Cast может упростить эту задачу.

1
Josh Kelley 8 Окт 2014 в 19:39