我知道这个问题已被提出;但它没有一步一步地解释,或者彻底解释它是如何被执行的;所以,假设我有这部分代码:
char ch;
while((ch = getchar()) != '\n' && ch != EOF);
getchar()是否将单个字符读入ch变量1st,然后进行比较,即ch != '\n' && ch != EOF
,保留新行转义序列缓冲,但实际上不在ch变量中?如果是这样,这是不是意味着它会无限循环直到它遇到换行转义序列/ EOF?如果遇到换行转义序列,它是否存储在ch变量中?如果没有,怎么回事?
答案 0 :(得分:7)
char ch;
首先,我们定义ch
类型的char
变量。
while((ch = getchar()) != '\n' && ch != EOF);
这是一个while
循环。循环条件为(ch = getchar()) != '\n' && ch != EOF
,循环体为;
(空语句)。
循环条件包括&&
(逻辑"和")和两个操作数(ch = getchar()) != '\n'
和ch != EOF
。 &&
运算符始终首先计算其左操作数。
(ch = getchar()) != '\n'
是一种不平等比较。右侧是'\n'
(表示换行符)。左侧是赋值表达式ch = getchar()
。
getchar()
调用getchar
函数,该函数从stdin
(标准输入)读取字符。如果成功,则以unsigned char
的形式返回此字符(通常在0 ... 255范围内);否则(如果getchar
失败)它返回EOF
(这是一个(特定于实现的)负值)。这就是getchar
的返回类型为int
的原因:它需要将所有有效字符值和表示为错误指示符。
此值存储在ch
中。此时,有两种可能性:
char
是您的实施中的无符号类型。在这种情况下,每个成功读取的字符都按原样存储,但EOF
将映射到某个正常字符。如果(通常情况下)EOF
的值为-1
,则最终会变为UCHAR_MAX
(通常为255)。
char
是您实施中的签名类型。在这种情况下,所有可能的字符值中有一半超出范围(通常签名char
的范围为-128 .. 127,并且无法存储128 ... 255的值。这里的事情有点模糊:超出范围的字符将导致(实现定义的)信号或将转换为其他(实现定义的)字符。另一方面,EOF
可能会保留原样(除非它的值小于CHAR_MIN
,在这种情况下,您获得实现定义的信号或转换,如前所述)。
赋值表达式具有赋值后左操作数的值。因此(ch = getchar())
返回ch
的新值(如上所述,它是输入字符的修改)。我们将此字符与'\n'
(换行符)进行比较。如果是换行符,!=
会产生错误,&&
会立即产生错误,并且循环停止。 (请注意,根据您的实现,其他字符甚至EOF可能会被错误检测为'\n'
,因为上面描述了错误。)
如果输入字符不是换行符,!=
将返回true,&&
继续评估其右侧操作数。在这里,我们比较ch != EOF
。如果我们遇到#1(即char
是无符号类型),则此比较始终为真,因为EOF
是负值(除非我们处于更奇特的情况并且{{1} } / char
具有相同大小/范围的可能值,我不打算这样做。如果我们遇到#2(即int
是签名类型),如果char
返回getchar
(即输入的结束已达到或者是{1}},则此比较将返回false发生错误),循环停止。它也会将某些字符(通常为EOF
,255)误识别为UCHAR_MAX
。
否则(即EOF
不是ch
或'\n'
)循环重复,读取并检查下一个字符。
此代码的目的是使用和丢弃输入,直到达到换行符或输入结束。
但由于编写代码的方式,实际上它不会识别EOF
(因此在到达输入结尾时永远循环)或将有效输入视为EOF
(和因此早点结束。)
修复方法是将EOF
声明为ch
:
int