gets和scanf有什么区别?(涉及IT技术)

14

如果代码

scanf("%s\n",message)  

对比

gets(message)

它们之间有什么区别?似乎两者都将输入传递给消息。


1
scanf() 是标准的 C 函数,而 gets() 已经不再是标准函数。 - alk
6
大家是否都忽略了 gets 被有意弃用的事实?即使是4年前的回答也建议像避瘟疫一样避免使用 gets - user3920237
2
@remyabel,他们也没有提到scanf()同样不安全...而且每个人都忽略了可怜的fgets(),它应该是获取用户输入的唯一方法。 - The Paramagnetic Croissant
1
确实...我本来不想回答,但是看到这么多回答都忽略了这点,我觉得有必要指出一下。 - Lundin
1
@TheParamagneticCroissant:如果正确使用,scanf() 是完全安全的。 - alk
2
@alk 这是真的,但是正确使用 scanf() 比正确使用 fgets() 要难得多。 - The Paramagnetic Croissant
10个回答

23

针对您的特定情况,基本区别如下:

  • scanf()在遇到whitespacenewlineEOF时结束输入。

  • gets()将空格视为输入字符串的一部分,在遇到newlineEOF时结束输入。

然而,为了避免缓冲区溢出错误和减少安全风险,更安全的方法是使用fgets()


注意:scanf("%s\n",message)不会在遇到空格或换行符时停止输入。"%s\n"会导致scanf()执行以下操作:1)扫描所有的空白输入并将其丢弃;2)扫描所有的非空白输入并将其保存到message中,最后附加'\0';3)扫描所有的空白输入并将其丢弃,直到遇到一个非空白字符,该字符被放回到stdin以供下一次IO调用使用。 - chux - Reinstate Monica
@chux 谢谢您阐明。在我的回答中,我所说的“输入”是指将非空白字符存储到提供的缓冲区“message”中。然而,您的评论使得这个答案更加完整。 - Sourav Ghosh
亲爱的点踩者,如果您不仅仅是点踩而是留下评论,那么这将有助于我改进这个答案(以及下一个)。谢谢。 - Sourav Ghosh

7

澄清:在下文中,如果“safe”没有正确使用不会导致麻烦,则我认为其是“安全的”,如果无法规避“不安全性”,则认为其是“unsafe”。

scanf("%s\n",message)

vs

gets(message)

What's the difference?

就安全性而言,从标准输入读取数据的两种方法并无区别,都有可能导致message溢出,如果用户输入的数据超过message提供的内存空间。
而scanf()函数则允许您通过指定要扫描的数据的最大量来安全使用它:
char message[42];

...

scanf("%41s", message); /* Only read in one few then the buffer (messega here) 
                           provides as one byte is necessary to store the 
                           C-"string"'s 0-terminator. */

使用gets()函数无法指定读取的最大字符数,因此不应该使用该函数!

scanf()比gets不够安全,因为它的类型安全性降低了。 - Lundin
嗯,是的,但在开始争论之前,最好先定义“安全”。@Lundin - alk
“安全”是指“已知会导致错误、定义不清和程序崩溃”?在C语言中,我想不出还有比这更不安全的函数了。 - Lundin
@Lundin:如果像你在评论中刚刚定义的“unsafe”一样,我完全同意,scanf()是一个该死的、可恶的、该死的不安全的家伙。我几乎总是拒绝使用它。... - alk

5
主要区别在于gets读取到EOF或\n,而scanf("%s")读取到任何空格为止。 scanf提供更多的格式选项,但同时它的类型安全性比gets差。
另一个重大区别是scanf是标准C函数,而gets已被从语言中删除,因为它既是多余的又很危险:没有保护措施来防止缓冲区溢出。然而,scanf也存在同样的安全漏洞,因此这两个函数都不应该用于生产代码
您应该始终使用fgets,甚至C标准本身也建议这样做,请参见C11 K.3.5.4.1:

推荐实践

6. fgets函数允许正确编写的程序安全地处理太长以至于无法存储在结果数组中的输入行。一般情况下,这要求调用者在结果数组中注意换行符的存在或不存在。 请考虑使用fgets(以及基于换行符的任何必需处理),而不是gets_s。

(强调我的)


2
注意:scanf("%s")会读取并丢弃任何前导空格,然后扫描并保存非空格字符,直到随后的空格或EOF - chux - Reinstate Monica

4

gets - 从标准输入读取字符并将它们存储为字符串。

scanf - 从标准输入中读取数据,并根据scanf语句中指定的格式(如%d%f%s等)将其存储。


4
有几个区别。一个是gets() 只能获得字符字符串数据。另一个是gets() 一次只能获得一个变量。scanf() 则是一种更加灵活的工具,可以读取不同数据类型的多个项目。
在你选择的特定示例中,没有太大的区别。

3

gets:->

gets()函数从标准输入中读取一行,并将其存储到由指针s指向的缓冲区,直到遇到换行符或者EOF,然后用空字符('\0')替换它们。

BUGS:->

切勿使用gets()。因为在不知道数据长度的情况下,在使用gets()时无法确定它会读入多少个字符,并且gets()会继续存储超出缓冲区末尾的字符,所以使用它非常危险,它已经被用于破坏计算机安全。请改用fgets()

scanf:->

scanf()函数从标准输入流stdin读取输入;

BUG:->

有时候当涉及数组和字符串概念时,scanf会产生一些边界问题。


2
如果您引用了某些内容,请注明出处,并使用引用格式。 - Lundin

2
scanfgets不同,scanf需要指定格式,而gets则可以输入字符、字符串、数字和空格。 scanf在遇到空格时结束输入。
但是,在您的示例中,使用了“%s”,因此无论是gets()还是scanf()都需要确保字符串是有效的指向足够长的数组的指针。否则会导致缓冲区溢出。
提示:使用fgets(),但这完全取决于使用情况。

0

scanf 不接受空格的概念是完全错误的。如果您使用此代码部分,它将同时接受空格:

#include<stdio.h>
int main()
{
char name[25];  
printf("Enter your name :\n");
scanf("%[^\n]s",name);
printf("%s",name);
return 0;
}

在编程中,换行符只会停止输入。这意味着只有在按下回车键时才会停止输入。

因此,scanf和gets函数基本上没有区别。这只是一种巧妙的实现方式。


0

scanf() 是更加灵活的工具,而 gets() 一次只能获取一个变量。


-1

gets() 是不安全的,例如:char str[1]; gets(str) 如果你输入的内容超过了长度,它会以 SIGSEGV 结束。如果只能使用 gets,请使用 malloc 作为基本变量。


正如其他人所提到的,是的,使用gets()是不安全的,但是:如果您输入的内容超出了长度,那么怎么办?您如何在C中输入一个“字符串”的长度?您似乎把一些事情搞混了。 - alk

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