C - Есть ли способ прочитать один символ пользовательского ввода и не дать остальным «спуститься» к следующему запросу на ввод? - PullRequest
1 голос
/ 14 февраля 2020

Итак, я работаю над простой игрой на палаче в C, и у меня есть функция read_guess, показанная ниже.

void read_guess(char *guesses, char *p_current_guess)
{
    int valid_guess = 0;

    // Repeatedly takes input until guess is valid
    while (valid_guess == 0)
    {
        printf(">>> ");
        fgets(p_current_guess, 2, stdin);

        if (!isalpha(*p_current_guess)) printf("Guesses must be alphabetic. Please try again.\n\n");
        else
        {
            valid_guess = 1;

            // Iterates over array of guesses and checks if letter has already been guessed
            for (int i = 0; guesses[i] != '\0'; i++)
            {
                if (guesses[i] == *p_current_guess)
                {
                    printf("You have already guessed this letter. Please try again.\n\n");
                    valid_guess = 0;
                    break;
                }
            }
        }
    }
}

Я перепробовал все стандартные функции ввода (включая getchar ), но со всеми из них, когда вводится больше, чем один символ, вместо того, чтобы брать только первый символ и двигаться дальше (или спрашивать снова), остальная часть ввода «сдвигается назад», и вводится в следующий раз запрашивается, будь то, потому что входные данные содержали не алфавитный символ c или начинается следующий раунд, остальная часть входных данных обрабатывается автоматически. Это повторяется для каждого символа ввода.

Как мне избежать этого?

Ответы [ 3 ]

1 голос
/ 14 февраля 2020

Вы можете отбросить весь ввод до конца строки, каждый раз, когда вы хотите запросить ввод.

void skip_to_eol(FILE* f, int c)
{
    while (c != EOF && c != '\n')
        c = fgetc(f);
}
...
    char c = getchar(); // instead of fgets
    skip_to_eol(stdin, c);
1 голос
/ 14 февраля 2020

Вы используете fgets, что хорошо, но, к сожалению, не правильно ...

fgets читает до конца строки или не более чем на 1 меньше, чем число персонажа спросил. И, конечно же, оставшиеся символы остаются для следующей операции чтения ...

Идиоматический способ c заключается в том, чтобы обеспечить чтение до конца строки независимо от длины или, по крайней мере, до большая длина.

  1. Простой, но может дать сбой при вводе более чем символов SIZE:

    #define SIZE 64
    ...
    
    void read_guess(char *guesses, char *p_current_guess)
    {
        char line[SIZE];
        int valid_guess = 0;
    
        // Repeatedly takes input until guess is valid
        while (valid_guess == 0)
        {
            printf(">>> ");
            fgets(line, SiZE, stdin);                // read a line of size at most SIZE-1
            p_current_guess[0] = line[0];            // keep first character
            p_current_guess[1] = '\0';
            ...
    
  2. Надежный, но несколько более сложный

    /**
     * Read a line and only keep the first character
     *
     * Syntax: char * fgetfirst(dest, fd);
     *
     * Parameters:
     *  dest: points to a buffer of size at least 2 that will recieve the
     *         first character followed with a null
     *  fd  : FILE* from which to read
     *
     * Return value: dest if one character was successfully read, else NULL
     */
    char *readfirst(dest, fd) {
    #define SIZE 256              // may be adapted
        char buf[SIZE];
        char *cr = NULL;          // return value initialized to NULL if nothing can be read
        for (;;) {
            if(NULL == fgets(buff, sizeof(buff), fd)) return cr; // read error or end of file
            if (0 == strcspn(buff, "\n")) return cr;             // end of file
            if (cr == NULL) {                                    // first read:
                cr = dest;                        //  prepare to return first char
                dest[0] = buff[0];
                dest[1] = 0;
            }
        }
    }
    

    Затем вы можете использовать его просто в своем коде:

    void read_guess(char *guesses, char *p_current_guess)
    {
        int valid_guess = 0;
    
        // Repeatedly takes input until guess is valid
        while (valid_guess == 0)
        {
            printf(">>> ");
            fgetfirst(p_current_guess, stdin);
    
0 голосов
/ 14 февраля 2020

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

Что эквивалентно getch () и getche () в Linux?

...