这个非常简单的问题可能是一个非常简单的答案:
我正在阅读Pratta的“C Primer Plus”,他一直在使用这个例子
while (scanf("%d", &num) == 1)...
== 1真的有必要吗?似乎可以写一下:
while (scanf("%d", &num))
似乎不需要相等测试,因为scanf返回读取的对象数,1将使while循环成为真。是确保读取的元素数量正好为1还是完全多余的原因?
答案 0 :(得分:25)
在C中,0被评估为假,其他一切被评估为真。因此,如果scanf返回EOF(这是一个负值),则循环将评估为true,这不是您想要的。
答案 1 :(得分:9)
由于scanf
在文件末尾返回值EOF(-1),因此写入的循环是正确的。只要输入包含与%d
匹配的文本,它就会运行,并在第一个不匹配或文件结束处停止。
如果scanf
期待不止一个输入,那么一眼就会更清楚了....
while (scanf("%d %d", &x, &y)==2) { ... }
当第一次无法匹配两个值时,将退出循环,这可能是由于文件结束文件(scanf
返回EOF(-1))或输入匹配错误(例如输入xyzzy 42
与%d %d
不匹配,因此scanf
在第一次失败时停止并返回0 而不写入x
或y
)当它返回一些小于2的值时。
当然,在解析来自普通人的真实输入时,scanf
不是你的朋友。处理错误案件有很多陷阱。
编辑:更正了错误:scanf
在文件末尾返回EOF
,或者计算成功设置的变量数的非负整数。
关键点在于,由于C中的任何非零值都是TRUE
,因此无法在这样的循环中正确测试返回值很容易导致意外行为。特别是,while(scanf(...))
是一个无限循环,除非它遇到无法根据其格式转换的输入文本。
我不能强烈强调scanf
不你的朋友。 fgets
和sscanf
的组合可能足以进行一些简单的解析,但即使这样,它也很容易被边缘情况和错误所淹没。
答案 2 :(得分:3)
您正确理解了C代码。
有时,测试读取的项目数量的原因是有人希望确保在输入与预期类型不匹配时提前读取所有项目而不是scanf退出。在这种特殊情况下,这无关紧要。
通常,scanf是一个很差的功能选择,因为它不能满足人类用户的交互式输入需求。通常fgets和sscanf的组合会产生更好的结果。在这种特殊情况下,这无关紧要。
如果后面的章节解释了为什么某些编码实践比这个简单的例子更好,那就好了。但如果没有,你应该抛弃你正在阅读的书。
另一方面,您的替代代码并不完全是替代品。如果scanf返回-1,则执行while循环。
答案 3 :(得分:1)
虽然你是正确的,但并不是绝对必要的,有些人更喜欢它,原因有几个。
首先,通过比较1,它成为一个显式的布尔值(true或false)。如果没有比较,您将测试一个整数,该整数在C中有效,但在以后的语言中没有(如C#)。
其次,有些人会根据while([function])而不是while([返回值])读取第二个版本,并且通过测试函数暂时会混淆,当显然意味着测试返回时值。
这完全取决于个人偏好,就我而言,两者都是有效的。
答案 4 :(得分:1)
有人可能会在没有明确比较的情况下编写它(虽然参见JRL的答案),但为什么会这样呢?我会说无比较条件只应该用于具有显式布尔语义的值(例如isdigit()
调用)。其他一切都应该使用明确的比较。在这种情况下(scanf
的结果)语义显然是非布尔值的,因此显式比较是有序的。
此外,通常可以省略的比较通常是与零的比较。如果你觉得省略与其他东西比较的冲动(比如1
),最好三思而后行,确保你知道自己在做什么(再次参见JRL的答案)。
在任何情况下,当可以安全地省略比较并且实际上省略它时,条件的实际语义含义保持不变。如果您担心的话,它对结果代码的效率绝对没有影响。