【问题标题】:Why is gets() working correctly, but fgets() isn't?为什么 gets() 工作正常,但 fgets() 不工作?
【发布时间】:2015-09-01 20:16:44
【问题描述】:

我做了一个程序,发现了gets(),并使用它,它很棒,但是当我编译程序时它说gets很危险,所以我搜索了一个替代方案,即使gets()函数使它具有正确的输出,因为将来我宁愿使用不危险的替代方法,也就是我偶然发现 fgets() 的时候。我认为代码会编译相同并具有相同的输出,但是没有输出我的 if 语句。

代码如下:

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

int main()
{
        char qOne[10];
        char qTwo[10];
        char guess[40] = "My guess is that you are thinking of a\0";

        printf("TWO QUESTIONS\n");
        printf("Think of an object, and i'll try to guess it.\n\n");

        printf("Question 1) Is it an animal, vegetable, or mineral?\n");
        printf("\n> ");
        //gets(qOne);
        fgets(qOne, 10, stdin);

        printf("\nQuestion 2) Is it bigger than a breadbox? (yes/no)\n");
        printf("\n> ");
        //gets(qTwo);
        fgets(qTwo, 10, stdin);

        printf("\n");

        if(strcmp(qOne, "animal") == 0 && strcmp(qTwo, "no") == 0 ||strcmp(qOne, "animal") == 0 && strcmp(qTwo, "No") == 0)

                printf("%s squirrel.\n", guess);

        else if(strcmp(qOne, "animal") == 0 && strcmp(qTwo, "yes") == 0 ||strcmp(qOne, "animal") == 0 && strcmp(qTwo, "Yes") == 0)

                printf("%s moose.\n", guess);

        else if(strcmp(qOne, "vegetable") == 0 && strcmp(qTwo, "no") == 0 ||strcmp(qOne, "vegetable") == 0 && strcmp(qTwo, "No") == 0)

                printf("%s carrot.\n", guess);

        else if(strcmp(qOne, "vegetable") == 0 && strcmp(qTwo, "yes") == 0 ||strcmp(qOne, "vegetable") == 0 && strcmp(qTwo, "Yes") == 0)

                printf("%s watermelon.\n", guess);

        else if(strcmp(qOne, "mineral") == 0 && strcmp(qTwo, "no") == 0 ||strcmp(qOne, "mineral") == 0 && strcmp(qTwo, "No") == 0)

                printf("%s paper clip.\n", guess);

        else if(strcmp(qOne, "mineral") == 0 && strcmp(qTwo, "yes") == 0 ||strcmp(qOne, "mineral") == 0 && strcmp(qTwo, "Yes") == 0)

                printf("%s Camaro.\n", guess);


        printf("\nI would ask you if I'm right, but I don't actually care.\n");

        return 0;
}

这段代码的输出是(输入字符串“animal”和“yes”):

TWO QUESTIONS
Think of an object, and i'll try to guess it.

Question 1) Is it an animal, vegetable, or mineral?

> animal

Question 2) Is it bigger than a breadbox? (yes/no)

> yes


I would ask you if I'm right, but I don't actually care.

但是,当我只使用 gets() 而不是 fgets() 时,我的代码会给出正确的输出,即:

TWO QUESTIONS
Think of an object, and i'll try to guess it.

Question 1) Is it an animal, vegetable, or mineral?

> animal

Question 2) Is it bigger than a breadbox? (yes/no)

> yes

My guess is that you are thinking of a moose.

I would ask you if I'm right, but I don't actually care.

如何使用 fgets() 获得相同的输出?

【问题讨论】:

  • 不可以,可以。 gets() 将输入中的换行符替换为 \0,但 fgets() 保留它。
  • fgets()gets() 实际上可能在成熟的 C 库实现中正常工作。
  • 如果fgets() 没有在目标数组中留下一个尾随'\n',这意味着输入行比缓冲区长——这意味着其余的输入行的一部分留在原地等待下一个输入调用读取。你应该做一些事情来处理这种情况。 (例如,您可以只读取并丢弃字符,直到看到 '\n'EOF。)
  • 就像注释一样,gets 会在您的代码中引入一个故障点,并且从 2011 年修订版起不再是标准库的一部分。你真的不想将它用于任何事情。使用起来非常不安全。
  • Keith Thompson 在“如果 fgets() 没有留下尾随 '\n' ... 输入行比缓冲区长”中是正确的,这当然是最可能的原因。其他可能性包括:1) 出现文件结束并且最后一个字符不是'\n'。 2) 嵌入的'\0' 发生在'\n' 掩盖其存在之前。 3) fgets() 返回值未与 NULL 进行检查,缓冲区内容可能不确定。

标签: c arrays string


【解决方案1】:

fgets() 保留结尾行 '\n'gets() 不保留。然后比较失败。 @user3121023 添加代码以消除潜在的结束行。

if (fgets(qTwo, sizeof qTwo, stdin) == NULL) Handle_EOF();
qTwo[strcspn(qTwo, "\n")] = 0;

Removing trailing newline character from fgets() input


[编辑]

请注意@Keith Thompson 以上关于输入行过长的评论。

【讨论】:

  • OP:请注意fgets(),在保存'\n' 时需要一个+1 更长的缓冲区作为gets()。顺便说一句:很高兴使用gets() 放弃。
  • 当我添加那段代码时,我不知道Handle_EOF()是什么,我把代码放在fgets之后,但我还是有点迷茫。
  • @Asad Mahmood Handle_EOF() 表示您需要编写一些代码来处理这种情况。 fgets() 返回 qTwoNULL。当它返回 NULL 时,表示文件结束(stdin 已关闭)或很少发生输入错误。对于像这样的简单程序,建议if (fgets(qTwo, sizeof qTwo, stdin) == NULL) { puts("EOF Occurred"); return -1; }
  • 像魅力花蕾一样工作,+1 给你 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 1970-01-01
  • 2011-08-29
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多