2013-06-25 49 views
10
scanf(" %[^\n]",line); 

我的一个朋友建议使用fgets()读取行输入会比使用scanf()如上述声明一个更好的主意。他有理吗?使用scanf()读取一行并不好?

+1

应当SCANF( “%[^ \ n]的”,线);关闭大括号中的参数.. –

+0

他绝对是。我总是建议使用'fgets()'并完全避免'scanf()'。 – 2013-06-25 10:27:50

+0

@RaghuSrikanthReddy为什么不使用'scanf()'的完美例子。 – 2013-06-25 10:28:07

回答

17

char * fgets (char * str, int num, FILE * stream);可以安全使用,因为它避免了buffer overflow问题,它只扫描num-1个字符。

从流中读取字符并将它们作为C字符串存储到str中,直到读取了(num-1)个字符或达到换行符或文件结束时,以先发生者为准。

这里第二个参数num是要复制到str的最大字符数(包括终止空字符)。

例如,假设在您的代码中字符串数组容量仅为5字符,如下所示。

char str[5]; 
fgets (str, 5, fp); //5 =you have provision to avoid buffer overrun 

使用上述代码中,如果从fp输入端较长然后4字符,fgets()将读取只是第一4字符然后追加\0,并丢弃其它额外输入字符,只是存储5个炭在str[])。

scanf(" %[^\n]",str);将读到\n没有发现,如果输入的字符串长度超过4字符scanf()会造成buffer overflow(如scanf将尝试在str[]访问内存超出最大指数4)。

+1

感谢您的详细解释。如果我不知道输入字符串有多长时间,scanf()会是更好的选择吗? – amulous

+0

@ amulous:YuHao先生给了一个很好的链接。在那里阅读,'scanf()','printf()'系列函数适用于格式化输入/输出 –

2

简单的说:是的,fgets是更好的选择。

我看着你的scanf格式说明符,我很困惑。完全理解它的功能需要一些时间阅读man页面。

此外,您的scanf代码易受缓冲区溢出的影响。

保持简单,您将降低维护成本并避免难以发现错误!

+0

缓冲区溢出是恶魔。得到它了。谢谢。 – amulous

6

ÇFAQ具有大约scanf的问题的一些详细的解释:

更一般地,scanf被设计用于相对的结构化,格式化的输入(其名称实际上从‘SCAN格式化’派生)。如果你注意,它会告诉你它是成功还是失败,但它可以告诉你只是大约失败的地方,而不是如何或为什么。你几乎没有机会做任何错误恢复。

参见here的细节。

+0

非常好的链接谢谢 –

+0

这是一个非常有用的链接。谢谢! – amulous

3

fgets会比这更好scanf。 可以有以下与scanf问题如OP

1)缓冲区泄出鉴于@Grijesh

所建议

2)可能下一个scanf后,因为换行输入流中离开这将无法工作。 (如果你错过了空格)

3

是fgets是从标准输入中读取一行的更好和安全的方式。

此外,在代码中会有更多的可读性。看看你给出的scanf语句。

任何第二个看到它的人都会感到困惑。但是,fgets会有更多的可能性,这很容易理解。

+5

你反驳了你自己。也许你的意思是在你的第一句话中“fgets”。 –

+0

@Jim Balter谢谢你的纠正 –

1

不用fgets(...)而使用下面的代码片断:

char _x[7000]; 
    char* y; 
while (! feof (_f)) 
{ 
    fscanf(_f,"%[^\n]\n",_x); 
      y=x; 
}