сбой теста scanf внутри функции в C


Я пытаюсь сделать программу с простой игрой для пользователя, чтобы угадать число. Мой код ниже:

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

#define MAX 30
#define TRYING 5

void guessnumber(int, int, int *);

int main(void) {
    int mytry = 1;

    guessnumber(MAX, TRYING, &mytry);

    if (mytry <= TRYING)
        printf("Congratulations! You got it right in %d triesn", mytry);
    else
        printf("Unfortunately you could not guess the number in the number of tries predefinedn");

    printf("Endn");

    return EXIT_SUCCESS;
}

void guessnumber(int _n, int _m, int *_mytry) {
    srandom(time(NULL));
    int generated = 0, mynum = 0, test = 0;

    generated = rand() % (_n + 1);

    printf("Welcome to "Guess the number" n");
    printf("A number between 0 and %d was generatedn", _n);
    printf("Guess the number:n");

    while (*_mytry <= TRYING) {
        test = scanf(" %d", &mynum);

        if (test != 1 || mynum < 0 || mynum > MAX)
            printf("ERROR: please enter a valid number n");
        else
        if (mynum > generated)
            printf("Wrong! The number your trying to guess is smallern");
        else
        if (mynum < generated)
            printf("Wrong ! The number your trying to guess is biggern");
        else
            break;
        *_mytry = *_mytry + 1;
    }
}
Хорошо, теперь программа работает довольно хорошо, за исключением одной вещи: теста scanf. Это работает, если я пытаюсь ввести число из моего диапазона (отрицательное или выше моего верхнего предела), но это не удается, если я, например, пытаюсь ввести букву. Что он делает, так это то, что он печатает сообщение об ошибке _m раз, а затем он печатает "к сожалению, вы не смогли угадать число в количестве попыток предопределено " и "конец".

Что я делаю не так и как я могу это исправить?

2 2

2 ответа:

В случае ввода символа вы пытаетесь определить его правильно

  if(test!=1 ......
Но вы не предприняли никаких действий, чтобы исправить это.

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

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

Решение: при возникновении сбоя необходимо очистить входной буфер от существующего содержимого. Вы можете сделать что-то вроде

while ((c = getchar()) != '\n' && c != EOF);

Для очистки буфера от существующего содержимого.

При вводе буквы scanf() оставляет букву во входном потоке, так как она не соответствует спецификатору преобразования %d. Проще всего использовать getchar() для удаления нежелательного символа:

if (test != 1) {
    getchar();
}

Лучшим решением было бы использовать fgets() для получения строки ввода и sscanf() для разбора ввода:

char buffer[100];
while (*_mytry<=TRYING)
{
    if (fgets(buffer, sizeof buffer, stdin) == NULL) {
        fprintf(stderr, "Error in fgets()");
        exit(EXIT_FAILURE);
    }

    test=sscanf(buffer, "%d", &mynum);

    if(test!=1 || mynum<0 || mynum>MAX)
        printf ("ERROR: please enter a valid number \n");

    else if(mynum>generated)
        printf("Wrong! The number your trying to guess is smaller\n");

    else if(mynum<generated)
        printf("Wrong ! The number your trying to guess is bigger\n");

    else
        break;
    *_mytry=*_mytry+1;
}

В приведенном выше коде обратите внимание,что начальный пробел был удален из строки формата. Начальный пробел в строке формата приводит к тому, что scanf() пропускает начало пробелы, включая новые строки. Это полезно, когда первый спецификатор преобразования - %c, например, потому что любой предыдущий ввод может оставить новую строку. Но спецификатор преобразования %d (и большинство других спецификаторов преобразования) уже пропускает начальные пробелы, поэтому он здесь не нужен.

Кроме того, ваш код имеет srandom() вместо srand(); и вызов srand() должен быть сделан только один раз и, вероятно, должен быть в начале main(). Причем, идентификаторы с ведущими подчеркивания зарезервированы в C, поэтому вы должны изменить имена _m, _n, и _mytry.