关于K&R习题1-12代码修改后失效的技术疑问
关于K&R习题1-12代码修改后失效的技术疑问
嘿,这个问题其实是你在修改代码时踩了一个很经典的坑——重复调用getchar()带来的副作用,咱们慢慢拆解清楚:
首先得说你最初的代码为什么能正常工作:
你在外层循环读到一个字符ch后,先判断它是不是非空白字符,如果是,就进入内层循环——先输出当前的ch,然后继续读下一个字符,直到遇到空白或EOF再换行。整个过程里每个输入字符只会被读取一次,逻辑连贯,不会漏掉任何字符。
但修改后的代码就出大问题了!你在内层while的条件里连续写了4次(ch = getchar()),这意味着每判断一个条件分支,都会读取一个新的输入字符,而且每次赋值都会覆盖掉ch原来的值。举个实际的例子,假设输入是hello world:
- 外层循环读到'h',因为不是空白,进入if块;
- 进入内层while的条件判断:
- 第一个条件
(ch = getchar()) != ' ':读取'e'赋值给ch,判断不是空格,继续; - 第二个条件
(ch = getchar()) != '\n':读取'l'覆盖ch,判断不是换行,继续; - 第三个条件
(ch = getchar()) != '\t':读取'l'覆盖ch,判断不是制表符,继续; - 第四个条件
(ch = getchar()) != EOF:读取'o'覆盖ch,判断不是EOF,进入循环体输出'o';
- 第一个条件
- 再次进入内层while的条件判断,第一个动作是读入空格,赋值给ch,判断
空格 != ' '不成立,直接退出内层循环,输出换行。
你看,原本的"hello"里的h、e、l、l都被白白读取却没有输出,只留下了o,后续的字符也被乱序消耗,完全破坏了逐个处理字符的逻辑。
核心问题就是:在条件表达式里多次调用有副作用的函数(比如getchar(),每次调用都会消耗一个输入字符),会让逻辑彻底偏离预期。你本来是想判断当前的ch是不是空白/EOF,但实际上每次判断都在刷新ch的值,大部分读取的字符都没被处理就丢了。
如果想遵循K&R里“把赋值写在条件里”的建议,正确的做法是只做一次赋值,然后用这个值去判断所有条件,同时还要注意不要漏掉外层已经读到的那个非空白字符。修正后的代码应该是这样:
#include <stdio.h> int main(void) { int ch; // 这里用int就够了,EOF是int类型,long没必要 while ((ch = getchar()) != EOF) { if (ch != ' ' && ch != '\n' && ch != '\t') { putchar(ch); // 先输出外层读到的非空白字符 // 继续读取并输出后续的非空白字符 while ((ch = getchar()) != ' ' && ch != '\n' && ch != '\t' && ch != EOF) { putchar(ch); } putchar('\n'); } } return 0; }
这样既符合K&R的写法建议,又能保持和你最初代码一致的正确逻辑。
备注:内容来源于stack exchange,提问作者Anadelta
相关产品推荐
相关产品推荐

