何时/为什么使用fscanf()函数是个坏主意?

何时/为什么使用fscanf()函数是个坏主意?,c,pointers,file-io,C,Pointers,File Io,在中有一句有趣的话:“使用fscanf()函数几乎总是一个坏主意,因为它会在失败时将文件指针保留在未知位置。我更喜欢使用fgets()来获取每一行,然后sscanf()这样做。” 你能详细说明一下什么时候/为什么最好使用fgets()和sscanf()来阅读一些文件吗 想象一个文件有三行: 1 2b c 使用fscanf()读取整数时,第一行的读数很好,但第二行的fscanf()将使您处于“b”位置,不确定从那里执行什么操作。您需要一些机制来越过垃圾输入查看第三行 如果执行f

在中有一句有趣的话:“使用
fscanf()
函数几乎总是一个坏主意,因为它会在失败时将文件指针保留在未知位置。我更喜欢使用
fgets()
来获取每一行,然后
sscanf()
这样做。”


你能详细说明一下什么时候/为什么最好使用
fgets()
sscanf()
来阅读一些文件吗

想象一个文件有三行:

   1
   2b
   c
使用
fscanf()
读取整数时,第一行的读数很好,但第二行的
fscanf()
将使您处于“b”位置,不确定从那里执行什么操作。您需要一些机制来越过垃圾输入查看第三行

如果执行
fgets()
sscanf()
,则可以保证文件指针一次移动一行,这更容易处理。一般来说,您仍然应该查看整个字符串以报告其中的任何奇数字符


我自己更喜欢后一种方法,尽管我不同意“使用
fscanf()
”这句话
fscanf()
在大多数情况下都很好。

基本上,没有办法告诉该函数不要超出您为其分配的内存区域的界限

已经出现了许多替代方法,如fnscanf,它试图通过指定读卡器写入的最大限制来修复这些函数,从而使其不会溢出。

当fscanf()由于输入失败或匹配失败而失败时,文件指针(即,文件中读取下一个字节的位置)保留在fscanf()成功的位置以外的位置。这在顺序文件读取中通常是不可取的。一次读取一行会导致文件输入是可预测的,而单行故障可以单独处理

使用
fscanf()
函数几乎总是一个坏主意,因为它会在出现故障时将文件指针留在未知位置。我更喜欢使用
fgets()
来输入每一行,然后
sscanf()
这样做


您可以始终使用
ftell()
查找文件中的当前位置,然后决定从该位置执行什么操作。基本上,如果您知道您可以期望的内容,请随意使用
fscanf()

当您匹配字符文字时,这一点就会发挥作用。假设您有:

int n = fscanf(fp, "%d,%d", &i1, &i2);
考虑两种可能的输入“
323、A424
”和“
323A424

在这两种情况下,
fscanf()
将返回1,下一个读取的字符将是
'A'
。无法确定逗号是否匹配

也就是说,只有在找到错误的实际来源很重要的情况下,这才有意义。在知道输入错误的情况下,
fscanf()
实际上优于编写自定义解析代码。

有两个原因:

  • scanf()
  • 整个
    scanf()
    系列将指针作为参数,但没有长度限制,因此它们可能会溢出缓冲区并更改缓冲区后面的不相关变量,导致看似随机的内存损坏错误,很难理解、查找和调试,尤其是对于经验较少的C程序员
新手C程序员经常对指针和“address of”操作符感到困惑,经常在需要的地方省略
&
,或者在不需要的地方添加它。这会导致他们很难找到“随机”segfault。这不是
scanf()
“这是我的错,所以我把它从我的清单上删除了,但这一点值得记住。”

23年过去了,我仍然记得当我开始C编程时是一个巨大的痛苦,我不知道如何识别和调试这些类型的错误,而且(作为一个花了多年时间教初学者C的人)很难向一个还不懂指针和堆栈的新手解释这些错误

任何向C程序员新手推荐
scanf()
的人都应该受到无情的鞭打


好的,也许不是无情的,但某种类型的鞭笞肯定是正确的;o)

虽然缓冲区溢出是scanf()函数家族的一个问题,但它们与这里所问的问题无关-1“你能详细说明为什么使用fgets()和sscanf()来读取一些文件会更好吗?”我正在详细说明他的问题。我拒绝你过于雄心勃勃的“-1”我接受“扩展为什么”,意思是你的答案应该基于已经提出的前提,即文件指针问题。如果他想知道其他原因,他就不会把问题的来源联系起来,也不会引用问题的相关部分。我把它理解为真正的“其他原因”,因为他已经解释了问题中的原因;)我想,不同的人读的是同一个问题。由于引用的原始问题与使用fscanf()阅读整行有关,因此与fgets()的比较和对缓冲区的关注比文件指针在不匹配时落在何处的问题更相关,尽管这是另一个线程中引用的示例。请将
gets()
更改为
fgets()
gets()
永远不应该被使用。肯定是打字错误:)谢谢你捕捉到了这一点。语句“将指针作为参数,但没有长度限制”是误导性的:对于大多数类型,大小是固定的(
%i
%d
%lf
),因此不需要长度限制。一个例外是使用
%s
读取字符串。但即便如此,还是有一个限度