在失败后{n}扫描输入流上剩余的内容

时间:2019-01-16 21:31:28

标签: c scanf

几年前,我使用K&R 2nd Edition ANSI C学习了C语言。我一直在阅读笔记,同时从另外2本书中学习了更现代的C语言。

我注意到K&R从来没有在书中使用scanf,除非他们介绍了scanf。他们主要使用他们在书中编写的getline函数,一旦引入了指针,便会在书中对其进行更改。那里的getline与gcc的getline是不同的,这导致我遇到了一些问题,直到我将getline的名称更改为ggetline为止。

查看我的笔记,我发现这句话:

  

这种简化既方便又肤浅,并且   尽其所能。问题是scanf不能正常工作   在更复杂的情况下。在7.1节中,我们说过   putchar和printf可以交错。并非总是如此   的scanf:如果您尝试混合调用,可能会遇到莫名其妙的问题   用调用getchar或getline进行scanf。更糟糕的是,事实证明   scanf的错误处理不足以用于许多目的。它告诉你   转换是否成功(更准确地说,它告诉您   成功完成了多少次转化),但没有告诉您更多信息   除此之外(除非您非常仔细地询问)。像atoi和atof,scanf   在处理%d或%f输入时停止读取字符   查找一个非数字字符。假设您已经提示用户   输入数字,而用户不小心输入了字母“ x”。扫描   可能返回0,表示它无法转换数字,但是   除非您无法转换的文字(x)保留在输入流中   找出其他删除方式。

     

由于这些原因(以及其他几个原因,我不会去理会   提及),通常建议不要将scanf用于   非结构化输入,例如用户提示。读起来更好   像getline这样的整行(因为我们一直在做所有   ),然后以某种方式处理这条线。如果该行应该   如果是一个数字,则可以使用atoi或atof进行转换。如果   该行具有更复杂的结构,您可以使用sscanf(我们将   一分钟见面)进行解析。 (最好使用sscanf而不是scanf   因为当sscanf失败时,您可以完全控制自己的工作   下一个。另一方面,当scanf失败时,您将受到   在输入流中它离开了您的位置。)

起初我以为这句话来自K&R,但我在书中找不到。然后我意识到那是从我上线的讲义中得到的,对于几年前使用K&R书籍教过课程的人来说。

lecture notes

我知道K&R书现在已有30年历史了,所以在某些方面过时了。

这句话很老了,所以我想知道scanf是否仍然有这种行为或改变了?

scanf失败时,是否还会在输入流中留下东西?例如上面的

  

假设您已经提示用户输入数字,并且用户   不小心输入字母“ x”。 scanf可能返回0,表示   它无法转换数字,但无法转换的文字(   'x')保留在输入流上。

以下内容是否仍然正确?

  

putchar和printf可以交错。并非总是如此   的scanf:如果您尝试混合调用,可能会遇到莫名其妙的问题   通过调用getchar或getline进行scanf。

自从以上引文被编写以来,scanf发生了很大变化吗?还是今天仍然适用?

我问的原因是,在我正在阅读的新书中,没有人提到这些问题。

1 个答案:

答案 0 :(得分:3)

scanf()是邪恶的-使用fgets()然后解析。


细节并不是scanf()完全不好。

1)格式说明符经常以较弱的方式使用

char buf[100];
scanf("%s", buf); // bad - no width limit

2)错误地未检查返回值

scanf("%99[\n]", buf); // what if use entered `"\n"`?
puts(buf); 

3)如果输入与预期不符,则不清楚stdin中剩余的内容。

if (scanf("%d %d %d", &i, &j, &k) != 3) {
  // OK, not what is in `stdin`?
}

  

如果尝试将对scanf的调用与对getchar或getline的调用混合在一起,就会遇到莫名其妙的问题。

是的。许多scanf()呼叫在'\n'中留下尾随stdin,然后getline(), fgets()读为空行。 scanf() 不是用于阅读getline()fgets()更适合阅读 line


  

自从上面的引号写下来以来,scanf发生了很大变化吗?

在不弄乱代码库的情况下,只能进行太多更改。 @Jonathan Leffler

scanf()仍然很麻烦。 scanf()无法接受参数(格式之后)来指示要接受char *目的地的字符数。

某些系统添加了其他格式选项来提供帮助。

一个基本问题是:

用户输入是邪恶。与尝试在一个函数中完成所有这些操作相比,将文本输入作为一个步骤,限定输入,然后解析和评估其成功性要强得多。


安全性

scanf()的弱点以及编码人员很难编写scanf()的代码,这一直是黑客的金矿。

IMO,C缺少可靠的用户输入功能集。