几年前,我使用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书籍教过课程的人来说。
我知道K&R书现在已有30年历史了,所以在某些方面过时了。
这句话很老了,所以我想知道scanf是否仍然有这种行为或改变了?
scanf失败时,是否还会在输入流中留下东西?例如上面的
假设您已经提示用户输入数字,并且用户 不小心输入字母“ x”。 scanf可能返回0,表示 它无法转换数字,但无法转换的文字( 'x')保留在输入流上。
以下内容是否仍然正确?
putchar和printf可以交错。并非总是如此 的scanf:如果您尝试混合调用,可能会遇到莫名其妙的问题 通过调用getchar或getline进行scanf。
自从以上引文被编写以来,scanf发生了很大变化吗?还是今天仍然适用?
我问的原因是,在我正在阅读的新书中,没有人提到这些问题。
答案 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缺少可靠的用户输入功能集。