清除 fgets 缓冲区

Clear fgets buffer

提问人:Riccardo Ricci 提问时间:11/10/2023 最后编辑:Riccardo Ricci 更新时间:11/10/2023 访问量:103

问:

我的代码有问题。

int startProg()
{
    char *method;
    method= malloc(30*sizeof(char));
    int isInteger=0;
    int num;
    do{

        printf("Seleziona il metodo \n");
        fgets(method,30,stdin);

        //it must be nothing more than 1 char inside 
        if (method[1]!= 10)
        {
            printf("Insert just one char  \n");
        }else{

            if (method[0]>='1'&&method[0]<='4'){

                 switch (method[0]){
                    case '1':
                        num=1;
                        break;
                    case '2':
                        num=2;
                        break;
                    case '3':
                        num=3;
                        break;
                    case '4':
                        num=4;        
                        break;
                }
                isInteger=1;
                //check the option choose
            }else{
                printf("Inserire un carattere valido\n");
            }
        }
    }while(isInteger==0);
    free (method);
    return num;
}

//terminal output
Seleziona il metodo 
123456789123456789123456781345646       
Inserire solo un carattere  
Seleziona il metodo 
Inserire solo un carattere  
Seleziona il metodo 

这个想法是接收用户输入,检查是否是 1 到 4 之间的数字,检查女巫值是,然后返回值。 唯一的问题是,当我插入一个超过 30 位的值时。 我必须清理缓冲区,并且我需要我的代码是可移植的。 有人有想法吗? 谢谢

C fgets

评论

0赞 Jabberwocky 11/10/2023
OT:不要使用像 和 这样的幻数,而是使用 和 。你在案例标签中这样做,那么为什么不在其他地方呢?4952'1''4'
0赞 GoWiser 11/10/2023
这个问题是 stackoverflow.com/questions/2532425/ 的重复......
0赞 GoWiser 11/10/2023
这回答了你的问题吗?在不知道行长度的情况下从文件中读取行
1赞 tnavidi 11/10/2023
似乎没有回答这个问题,OP 只想使用输入 1 到 4,但如果数字
2赞 Gerhardh 11/10/2023
(method[1]!= 10如果你的意思是,你应该使用'\n''\n'

答:

2赞 pmg 11/10/2023 #1

我认为如果输入大于保留的缓冲区,则要清除所有字符直到行尾fgets()

因此,请检测是否是这种情况

    if (!fgets(method, 30, stdin)) exit(EXIT_FAILURE);
    size_t len = strlen(method);
    if (len == 0) exit(EXIT_FAILURE); // input with '\0'????
    if (method[len - 1] != '\n') {
        // there is still data from the line in the input buffer
        clearEOL();
    }

您可以作为以下示例之一实现:clearEOL()

void clearEOL(void) {
    int ch;
    do {
        ch = getchar();
    } while ((ch != '\n') && (ch != EOF));
}

有些人可能更喜欢for循环:-)

void clearEOL(void) {
    for (int ch = getchar(); (ch != '\n') && (ch != EOF); ch = getchar()) /* void */;
}

甚至是无限循环与内部break

void clearEOL(void) {
    for (;;) {
        int ch = getchar();
        if (ch == '\n') break;
        if (ch == EOF) break;
    }
}

评论

0赞 Riccardo Ricci 11/10/2023
久经考验
1赞 Andrew Henle 11/10/2023
if (method[len - 1] != '\n')如果读取长度为零的字符串,则将在缓冲区外部读取。fgets()
1赞 pmg 11/10/2023
@AndrewHenle,首先应该测试结果。When 不返回时,字符串将不是空字符串(假设输入中没有字节)。答案已编辑。fgets()fgets()NULL'\0'
-1赞 Anthony C Howe 11/10/2023 #2

您正在为单个字符输入分配不必要的缓冲区。此外,如果没有更多输入,您应该处理 EOF(来自终端)。此代码利用了 ASCII 属性,其中数字 to 是一个连续的范围,EBCDIC(IBM 的字符编码系统)也是如此。^D09

(经过修订以处理 和abc1abc41)

#include <ctype.h>
#include <stdio.h>

/*
 * Return a value between 1..4 inclusive or 0 for EOF.
 */
int
startprog()
{
    int ch, num;

    do {
        num = 0;
        (void) printf("\rchoice (1-4): ");
        while ((ch = getchar()) != EOF && isdigit(ch)) {
            num = num * 10 + (ch - '0');
        }
    } while (ch != EOF && (num < 1 || 4 < num));

    return num;
}

int
main(int argc, char **argv)
{
    (void) printf("your choice %d\n", startprog());

    return 0;
}

评论

1赞 Jabberwocky 11/10/2023
不确定他们想要这个。考虑如果输入为 。ABC1ABC
0赞 Anthony C Howe 11/10/2023
@Jabberwocky OP 没有具体说明输入的确切性质。stdio 输入被缓冲,因此在找到有效数字之前,不必要的输入将被忽略。
1赞 Riccardo Ricci 11/10/2023
是的,但是如果用户插入 41,例如,我想接收错误而不是 4
0赞 Riccardo Ricci 11/10/2023
谢谢,就像我说的,我很想用 fgets 来学习新东西。我让 alredy 用 char 代码制作了这样的函数,但我的 ex 处理 41 有问题。谢谢你的提示
0赞 Andrew Henle 11/10/2023
@Jabberwocky 如果用户输入 ,则此代码将调用未定义的行为,因为有符号整数溢出。1412314123122312412312312412312341
0赞 Riccardo Ricci 11/10/2023 #3

我以明确的方式重写我的代码 (加时赛)我知道我不需要 malloc 和其他的,只是为了尝试我仍在学习哈哈。 现在的代码是

void clearEOL() {
    int ch;
    do {
        ch = getchar();
    } while ((ch != '\n') && (ch != EOF));
}
int startprog()
{
    int num;
    char option[25];
    int isInt=0;
    do{

        printf("insert a numer (1/4)  \n");
        fgets(option,20,stdin);
        if(option[1]!='\n' || option[0]=='\n'){

             printf("Inserire solo un carattere  \n");
            clearEOL();
        }else
        {
            if ('1'<=option[0]&&option[0]<='4'){

                num=(option[0]-='0');
                isInt=1;
            }else{

                printf("Inserire 1 e 4\n");
                clearEOL();
            }

        }


    }while(isInt==0);
    return num;
}



评论

0赞 Anthony C Howe 11/10/2023
在EOF的情况下,应进行测试结果。此外,它比硬编码大小更安全。fgets() == NULLfgets(option, sizeof (option), stdin)
1赞 pmg 11/10/2023
如果输入是空行 ( 和 ),则将从用户那里清除下一行!!option[0] == '\n'option[1] == '\0'clearEOL()
0赞 Riccardo Ricci 11/10/2023
我试着把这条线(option[1]!='\n' || option[0]=='\n'),让我知道它是否正确。如果我没有收到正确的值,我必须按回车键才能继续。这正常吗?
0赞 pmg 11/10/2023
即使阅读了一整行,您也在打电话。您需要测试最后一个字符是否为换行符!clearEOL()fgets()
0赞 Anklon 11/11/2023
你的回答没有解决问题的根源是什么,为什么会这样,以及你的回答如何解决问题。它不会帮助其他面临同样问题的人。