为什么gets()函数无法读取完整的输入行?

5

我试图使用gets()从用户获取一个字符串,但程序似乎直接跳过了gets()。没有暂停等待用户输入。为什么gets()没有起作用?

char name[13];
printf("Profile name: ");
gets(name);
printf("\n%s", name);

1
@DerekDrummond 输入为12个字符,最后一个必须是 '\0' - Kevin
2
请使用fgets(name, sizeof name, stdin)代替gets(),这个问题已经被回答了很多次,请查看其中一个答案:http://stackoverflow.com/questions/7231349/getsstring-function-skipping-first-gets-request?rq=1 - Gangadhar
2
不要使用 scanf 读取字符串。请使用 fgets - Kninnug
1
我认为您可以在 scanf 格式的末尾留下一个空格,以便它消耗输入中的任何空格(例如尾随换行符)。但请不要引用我说的话。 - Kninnug
1
我尝试使用fgets(name, sizeof name, stdin),但它被跳过了。很遗憾gets()曾经是如此简单,现在被笨重的东西所取代。 - Yan King Yin
显示剩余5条评论
7个回答

7
在调用gets()或fgets()之前,请先调用getchar()。由于gets()或fgets()由于stdin中以前输入的'\n'而被跳过,调用getchar()会导致它自己被跳过,而不是gets()、fgets()或任何其他类似的函数。但请记住这更像是一种hack而不是标准解决方案(我认为是这样),同时禁止使用gets()。
        printf("\nEnter a String: ");
        getchar();
        //fgets(inputString, 100, stdin);
        gets(inputString);
        printf("\n%s", inputString);

5

之所以gets()如此危险,以至于一些C库已经将其完全删除,并用一个什么也不做的版本替换了它。

请使用fgets()代替。


3
在C11中,“gets”已被正式移除,并在C++中被弃用。 - Linuxios

3
在使用gets()之前,请使用fflush(stdin);。

这是对我有效的解决方案,另一个没有。谢谢@Aadil Ansari。 - Joe Gasewicz

2
你使用gets()会遇到很多麻烦,建议使用fgets()代替。
fgets(name,13,stdin);  

看这篇 Stack Overflow 的问题 为什么 gets 函数是如此危险,不应该使用? fgets() 不起作用的原因可能是您没有处理前面语句中 scanf 留下的换行符。
您可以修改您的 scanf 格式字符串以考虑它: scanf("%d *[^\n]", &N); *[^\n] 表示忽略整数输入后面不是换行符的所有内容,但是不要对换行符做任何处理(跳过它)。
当您使用 scanf("%d",&num) 时,您会输入数字 13 和回车,然后 13 存储在 num 中,而换行符仍然存在于输入缓冲区中。当您从 stdin 中读取 fgets 时,它会将 \n 视为您输入的数据,因此跳过了 fgets() 语句。
你无法清空输入缓冲区,但可以在每个 fgets 语句之前添加 fseek(stdin,0,SEEK_END); 来实现此操作。

@Andre,你能把你的完整代码贴出来吗?这样我们能看看它是否能够在这里运行。 - niko
void createProfile() { char name[13]; printf("个人资料名称:"); fgets(name,13,stdin); printf("\n%s", name); } - Ace
你的代码中有没有使用scanf()函数,@Andre?因为scanf()函数只会读取你要求它读取的内容,而忽略其他内容,尤其是数据后面的换行符。 - niko
是的,我之前用过几次。那么你的意思是我只应该使用fgets吗? - Ace
建议使用 fgets(name, sizeof(name), stdin) - chux - Reinstate Monica
显示剩余2条评论

1
请看 gets()参考文献 从标准输入中获取字符串 从标准输入(stdin)读取字符,并将它们作为C字符串存储到str中,直到遇到换行符或文件结束符为止。
如果找到换行符,则不会复制到str中。
在复制到str后,自动追加一个终止空字符。
注意,gets与fgets非常不同:gets不仅使用stdin作为源,而且不包括结果字符串中的结束换行符,并且不允许指定str的最大大小(这可能导致缓冲区溢出)。
因此,gets()不仅不安全(可能导致缓冲区溢出),而且读取了输入缓冲区中的内容。
我建议您使用fgets(),但如果您想要快速(和懒惰和愚蠢)解决方案,请清除输入缓冲区。
char name[13];
printf("Profile name: ");
fflush(stdin);
gets(name);
printf("\n%s", name);

3
在C语言中,调用fflush(stdin)是未定义的行为。 - digital_revenant
你说得对,它应该与输出缓冲区一起使用。然而,一些编译器将fflush(stdin)实现为扩展。它的工作效果符合预期,但会影响可移植性。 - fvdalcin
2
是的,然而语言标准将其视为未定义行为。不应鼓励使用它。 - digital_revenant

1
将以下函数添加到您的代码中,然后享受它。
string GetString()
{
   char ch;
   string Line="";

   while(1)
   {
       ch=getchar();

       if(ch=='\n')
          break;
       else
          Line+=ch;
    }

    return Line;
}

这个功能会影响所有的空格和退格符号!!!


0
您可能需要放弃本行的剩余部分并转到下一行的开头。您可以这样做:
int c; while((c=getchar()) != '\n' && c != EOF);

这会丢弃当前行的其余部分(可能已经被scanf()等部分读取),并继续到下一行。

虽然fflush(stdin)也可以丢弃输入,但这是非标准行为,不建议使用。

您永远不应该使用gets(myString),因为它已经完全从C标准中删除,由于其不安全性。它不强制执行字符串的长度,因此您可以超过缓冲区的末尾并覆盖RAM中的其他值,导致缓冲区溢出,这可能是安全漏洞。请改用fgets(myString, myStringSize, stdin)。要消除结果字符串中的换行符,请使用myString[strcspn(myString, "\n")] = 0;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接