fgets и sscanf пропускаются в c? - PullRequest
       56

fgets и sscanf пропускаются в c?

0 голосов
/ 02 февраля 2020

В своем коде я проверяю, что пользователь вводит один из следующих сокращенных классов, однако мои fgets вызывают у меня множество ошибок c в логах.

char class[3];
char arr3[5];
i = 0;
    while(i == 0){
        printf("Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO\n");
        fgets(arr3, sizeof(arr3), stdin);

        if(sscanf(arr3, "%s", class) == 1){

            if(strcmp(class, "FR\0") == 1 || strcmp(class, "SO\0") == 1)
                i = 1;
            else if(strcmp(class, "JR\0") == 1 || strcmp(class, "SR\0") == 1)
                i = 1;
            else if(strcmp(class, "GR\0") == 1 || strcmp(class, "RFR\0") == 1)
                i = 1;
            else if(strcmp(class, "RSO\0") == 1)
                i = 1;
            else
                printf("Enter one of the classes.  Must be all caps.\n");
        }
        else if(sscanf(arr3, "%s", class) != 1)
            printf("An error has occured.\n");
    }

Когда я запускаю код, первое, что происходит, это то, что он пропускает fgets и затем печатает: введите один из классов. Должны быть все заглавные буквы. Значит ли это, что он читает что-то, что уже есть в stdin?

1 Ответ

2 голосов
/ 02 февраля 2020

Продолжая мой комментарий, вы ошибаетесь во многих вещах, но самое большое - Не экономьте на размере буфера! . Ваша следующая главная путаница в том, что strcmp возвращает НОЛЬ при совпадении строк, а не 1. Не пытайтесь удалить конечный '\n', включенный fgets путем усечения до более короткого массива, просто используйте strcspn для его удаления.

A String Literal обеспечивает nul-termianting символа, поэтому "\0" в "SR\0" является излишним. Избавьтесь от них.

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

Внося эти изменения, вы можете сделать:

#include <stdio.h>
#include <string.h>

#define BUFC 1024       /* if you need a constant, #define one (or more) */

int main (void) {

    char buf[BUFC];

    while (1) {
        printf("Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO\n");
        if (!fgets (buf, BUFC, stdin)) {
            fputs ("(user canceled input)\n", stdout);
            return 1;
        }
        buf[strcspn (buf, "\n")] = 0;       /* trim newline from buf */

        /* strcmp equality return is 0 */
        if (strcmp (buf, "FR") == 0 || strcmp (buf, "SO") == 0  ||
            strcmp (buf, "JR") == 0 || strcmp (buf, "SR") == 0  ||
            strcmp (buf, "GR") == 0 || strcmp (buf, "RFR") == 0 ||
            strcmp (buf, "RSO") == 0)
            break;
        else
            printf("Enter one of the classes.  Must be all caps.\n");
    }
    printf ("\nclass: %s\n", buf);
}

( примечание: , если вы компилируете для микроконтроллера, такого как Arduino или TI- MSP432, с ограниченной памятью, тогда вы можете уменьшить BUFC до 32 или около того, но на x86 или x86_64 буфер от 1K до 4K обычно гарантирует, что все обычные строки ввода будут использованы - даже если cat переходит на клавиатура)

Выше проверка возврата fgets() позволяет поймать сгенерированный вручную EOF, где пользователь отменяет ввод, нажимая Ctrl + d на Linux или Ctrl + z on windows.

Пример использования / Вывод

$ ./bin/enterclasses
Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO
banannas
Enter one of the classes.  Must be all caps.
Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO
NO
Enter one of the classes.  Must be all caps.
Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO
RFR

class: RFR

Посмотрите вещи и дайте мне знать, если у вас есть еще вопросы.

...