K&R《C语言》书中的一个Bug
2014-06-17 22:27
309 查看
最近在重温K&R的C语言圣经,第二章中的练习题2-2引起了我的注意。
原题是:
题目里说的for循环是下面这个:
不能用&&和||运算符,又要与for循环中的3个条件表达式等价,怎么改呢?
因为书中这一节正在讲关系运算符和逻辑运算符,其中提到了当表达式结果为true时的值实际上是整数1,为false时为0,即:
所以我想到了一种方法:
3个表达式都成立,也就是说它们的值都是1,所以和为3。
看起来好像没问题,但是我发现这么修改却是不对的。
因为在原程序里的3个表达式是有先后次序并且有“短路”关系的——当第一个表达式“i<lim-1”为false时,后面两个就不会再执行了;而且也不应该执行,否则就会导致字符丢失。
为什么呢?假如现在缓冲区里有字符“abcdefg”,lim为3:
当i为2时,“i<lim-1”为false,如果程序是非短路的,此时会继续执行后面的c=getchar(),就会把第3个字符即"c"读取出来,但由于整个循环的条件为false,因此不会执行赋值语句“s[i]=c”,所以这个字符就这么丢失了。
而我修改后的程序恰恰是非短路的!但我却想不出来一个可以和原程序完全等价的方案。
评论中@剑指天涯不可挡 和 @nicozhang 两位朋友指出可以用条件表达式或将条件判断放到循环体中来解决这个问题。但是书中到目前为止还没有介绍if语句和条件表达式。如果这个题目是想考察if语句或条件表达式,那么它就不应该在这里出现。所以我觉得这是一个作者也没有考虑到的Bug,你不可能写出和原程序完全等价的程序而不用到&&和||。
毕竟两位作者也是人。
当然也可能是我错了,如果你有好的解决方案请不吝赐教。
20151016补充:
今天回过头来看这篇文章,重新思考这个问题,忽然想到一个解决方法:
把c用s[i]代替就不会出现上面所说的字符丢失的问题了。并且此时必须注意,第一个判断i < lim-1需要修改为i < lim-2。因为修改后的条件表达式不是短路的,如果不这样修改,那么当i等于lim-1时并不会马上退出循环,而是会继续执行后面两个子表达式,然后才退出循环,这样程序就错了。
因此这道题并没有Bug,2位大师是冤枉的,我在此郑重向他们道歉!
原题是:
Write a loop equivalent to the for loop above without using && or ||.
题目里说的for循环是下面这个:
for (i=0; i < lim-1 && (c=getchar()) != '\n' && c != EOF; ++i) s[i] = c;
不能用&&和||运算符,又要与for循环中的3个条件表达式等价,怎么改呢?
因为书中这一节正在讲关系运算符和逻辑运算符,其中提到了当表达式结果为true时的值实际上是整数1,为false时为0,即:
true == 1 false == 0
所以我想到了一种方法:
for (i=0; (i<lim-1) + ((c=getchar())!='\n') + (c!=EOF) == 3; ++i) s[i] = c;
3个表达式都成立,也就是说它们的值都是1,所以和为3。
看起来好像没问题,但是我发现这么修改却是不对的。
因为在原程序里的3个表达式是有先后次序并且有“短路”关系的——当第一个表达式“i<lim-1”为false时,后面两个就不会再执行了;而且也不应该执行,否则就会导致字符丢失。
为什么呢?假如现在缓冲区里有字符“abcdefg”,lim为3:
当i为2时,“i<lim-1”为false,如果程序是非短路的,此时会继续执行后面的c=getchar(),就会把第3个字符即"c"读取出来,但由于整个循环的条件为false,因此不会执行赋值语句“s[i]=c”,所以这个字符就这么丢失了。
而我修改后的程序恰恰是非短路的!但我却想不出来一个可以和原程序完全等价的方案。
评论中@剑指天涯不可挡 和 @nicozhang 两位朋友指出可以用条件表达式或将条件判断放到循环体中来解决这个问题。但是书中到目前为止还没有介绍if语句和条件表达式。如果这个题目是想考察if语句或条件表达式,那么它就不应该在这里出现。所以我觉得这是一个作者也没有考虑到的Bug,你不可能写出和原程序完全等价的程序而不用到&&和||。
毕竟两位作者也是人。
当然也可能是我错了,如果你有好的解决方案请不吝赐教。
20151016补充:
今天回过头来看这篇文章,重新思考这个问题,忽然想到一个解决方法:
// for (i=0; i < lim-1 && (c=getchar()) != '\n' && c != EOF; ++i) // s[i] = c; for (i=0; (i < lim-2) + ((s[i]=getchar()) != '\n') + (s[i] != EOF) == 3; ++i) ;
把c用s[i]代替就不会出现上面所说的字符丢失的问题了。并且此时必须注意,第一个判断i < lim-1需要修改为i < lim-2。因为修改后的条件表达式不是短路的,如果不这样修改,那么当i等于lim-1时并不会马上退出循环,而是会继续执行后面两个子表达式,然后才退出循环,这样程序就错了。
因此这道题并没有Bug,2位大师是冤枉的,我在此郑重向他们道歉!
相关文章推荐
- 谁能跟我编写一个程序(C语言)题目是编写一个函数计算sum(n)=1+2+3+。。。+n(n&gt;=1)
- 今天调试的一个bug,如果你懂c语言,不妨进来锻炼下眼力哦
- 【原创】关于在Objective-C中使用C语言数组的使用和NSArray的差别,以及由此可能产生的一个BUG
- 编程经验:一个由windows.h&&winbase.h引起的bug~
- 【C语言】要求找出具有下列性质的数的个数(包含输入的自然数n): 先输入一个自然数n(n<=500),然后对此自然数按照如下方法进行处理:
- 发现 ASP.Net 的一个关于"回车提交"的 Bug ? 必须多于一个 Text 域"回车提交",Server: ButtonX_Click 才能截获!
- 【反思】一个价值两天的BUG,无论工作还是学习C语言的朋友都看看吧!
- total commander在64位系统中的一个小"bug"
- 关于c语言的一个小bug(c专家编程)
- 【c语言】有一个函数: x < 1 --- y = x 1 <= x < 10 --- y = 2 * x - 1 x >= 10 --- y = 3 * x - 11 输
- 发现百度一个"Bug"
- 发现了magento 中"Shopping Cart Price Rules"一个bug
- C语言实现的计算一个文件下的所有文件的总大小(还有BUG,如果文件夹下面还有文件家就有问题,等待更新)
- C语言将多个字符串合并为一个字符串例如:数组[a,bbb,ccc]->字符串"a,bbb,ccc"
- Hive中LIKE查询使用通配符'%'的一个BUG--当转义符'\'遇到通配符'%'或'_'
- 一个正确的c语言链表代码(中间也有些bug)
- 关于'kksfbc child completion' wait的一个bug
- Django model default=datetime.datetime.now() & get_or_create 一个BUG?!
- 从修复 testerhome(rubychina)网站的一个 bug 学习 ruby&rails on ruby
- mysql&nbsp;存储过程的一个bug或者是我…