getchar() фактически не принимает ввод от пользователя

Я пишу гибкий генератор командной строки (но не долго!) В C++. Я только что закончил писать половину пользовательского ввода. Однако в самой последней команде ввод "проскальзывает", и в getchar() автоматически вводится символ новой строки. Я принял меры предосторожности, чтобы убедиться, что это не переполнение, а именно очистка как стандартного ввода, так и, по большей части, стандартного вывода. Проблема сохраняется. Вот мой код:

#include <stdio.h>
#include <stdlib.h>

int main () {
    unsigned  long seed = 0, x = 0, y = 0, initial = 0, range = 0;
    int smooth = 0, fail = 1;
    char flagchar1 = 'n';
    printf("Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. ");
    do {
        printf("Please input the seed (this is a positive integer):\n");
        fail = scanf("%lu", &seed);
        while (fail == 0) {
            printf("Try again, smartass.\n");
            fail = scanf("%lu", &seed);
        }
        fail = 1;
        printf("Now input the x, or horizontal, size of your grid:\n");
        fail = scanf("%lu", &x);
        while (fail == 0) {
            printf("An integer. Not a string. An integer. You can do that, can't you?\n");
            fail = scanf("%lu", &x);
        }
        fail = 1;
        printf("Now input the y, or vertical, size of your grid:\n");
        fail = scanf("%lu", &y);
        while (fail == 0) {
            printf("What was that supposed to be? An integer, please.\n");
            fail = scanf("%lu", &y);
        }
        fail = 1;
        printf("Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):\n");
        fail = scanf("%lu", &initial);
        while (initial == 0 || initial > 256 || fail == 0) {
            printf("ahahahahaha how HIGH do you have to be just to HAVE that hieght........\n");
            fail = scanf("%lu", &initial);
        }
        fail = 1;
        printf("Now input the range of the heights on your grid (this must be equal to or less than 256):\n");
        scanf("%lu", &range);
        while (range >= 256 || fail == 0) {
            printf("What did I say about being equal to or less than 256? Give me something reasonable to work with here.\n");
            fail = scanf("%lu", &range);
        }
        fail = 1;
        printf("Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!\n");
        fail = scanf("%d", &smooth);
        while (fail == 0) {
            printf("That... was not a number.\n");
            fail = scanf("%d", &smooth);
        }
        fail = 1;
        printf("\nOkay. Are these the values you want?\n   Seed:       %lu\n   Width:      %lu\n   Length:     %lu\n   Height:     %lu\n   Range:      %lu\n   Smoothness: %d\nDo you want to keep these? Type Y/n.\n", seed, x, y, initial, range, smooth);
        fflush(stdin);
        fflush(stdout);
        flagchar1 = getchar();
    } while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');
}

Вот мой вывод, программа закончилась (программа просто повторяет весь цикл do-while, если я удаляю && flagchar1 != '\n' от while()):

    Добро пожаловать в мой генератор алмазных квадратов! Это еще не полнофункциональный, так что я просто хочу, чтобы вы вводили переменные одну за другой. Пожалуйста, введите начальное число (это положительное целое число):
    12345678
    Теперь введите x или горизонтальный размер вашей сетки:
    40
    Теперь введите Y или вертикальный размер вашей сетки:
    30
    Теперь введите, насколько вы хотите, чтобы сетка была (это масштаб от 1 до 256):
    1288
    ахахахахаха, как ВЫ ДОЛЖНЫ быть, чтобы иметь ТО, ЧТО ВЫДАЛИ........
    128
    Теперь введите диапазон высот в вашей сетке (он должен быть равен или меньше 256):
    30
    Еще одна переменная! Теперь мне нужно, чтобы вы указали гладкость вашей сетки. Меньшие числа делают колючие сетки. Вы можете сделать это негативным, но будьте осторожны!
    10

Хорошо. Эти значения вы хотите?
  Семя: 12345678
  Ширина: 40
  Длина: 30
  Высота: 128
  Диапазон: 30
  Гладкость: 10
Вы хотите сохранить это? Тип Y/ N

Что происходит, и как мне это исправить?

PS Я знаю, что моя проверка ввода по существу бесполезна. Помощь с этим также высоко ценится.

5 ответов

Решение

Сделайте так, чтобы конец вашего цикла выглядел так:

    // Ignore remaining characters on current line.
    int ch;
    while( (ch = getchar()) != EOF && ch != '\n')
      ;
    // fetch first character on next line
    flagchar1 = getchar();
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');

Вы покидаете '\n' в stdin после вашего последнего звонка scanf,

Вы не должны полагаться на fflush(stdin) иметь какое-то конкретное поведение. Результат вызова fflush на входном потоке не определено. Смотрите Использование fflush(stdin)

Предложения:

  1. Используйте потоки C++.
  2. использование tolower или же toupper перед сравнением персонажей.
  3. использование std::string,

Язык C, который использует fgets, gets, fflush, strcmp, имеет много проблем в этой области. Язык C++ решил многие из этих проблем в std::stream классы.

Поскольку вы не используете функции C++, вы должны изменить тег C++ на C.

Я предполагаю, что вы работаете в Linux? Это отлично работает на VS в Windows. Он запрашивает, читает с клавиатуры и, если проверено, содержит правильные "y" или "Y" в вопросе.

Я мог бы предложить вам изменить последний сканф на:

fail = scanf("%d ", &smooth);

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

Конечный пробел попросит scanf использовать любые дополнительные пробелы (включая переводы строк) во входных данных. fflush(), вероятно, не будет делать то, что вы хотите для ввода.

Я подозреваю, что любая система, в которой вы находитесь, действительно оставляет возврат каретки в потоке, и если вы напечатаете flagchar1 как int, вы получите 10?

Код ведет себя именно так, как вы говорите. Если пользователь вводит "y", "Y" или вводит, одно из этих условий в цикле while будет ложным, что приведет к его выходу.

То, что вы хотите, это:

while (flagchar1 == 'y' || flagchar1 == 'Y' || flagchar1 == '\n');

Редактировать: я бы также удалил fflush(stdin) и заменил getchar() на fgets(). Это гарантирует, что вся строка будет прочитана без использования fflush, что может быть проблемой.

Пытаться

} while (flagchar1!= 'y' || flagchar1!= 'Y' || flagchar1!= '\n');

вместо

} while (flagchar1!= 'y' && flagchar1!= 'Y' && flagchar1!= '\n');

Другие вопросы по тегам