最近在重温K&R的C语言圣经,第二章中的练习题2-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位大师是冤枉的,我在此郑重向他们道歉!

转载于:https://www.cnblogs.com/antineutrino/p/3793625.html

KR《C语言》书中的一个Bug相关推荐

  1. C语言字符串中最后一个单词的长度的算法(附完整源码)

    C语言字符串中最后一个单词的长度的算法 C语言字符串中最后一个单词的长度的算法完整源码(定义,实现,main函数测试) C语言字符串中最后一个单词的长度的算法完整源码(定义,实现,main函数测试) ...

  2. 微软BI 之SSIS 系列 - MVP 们也不解的 Scrip Task 脚本任务中的一个 Bug

    开篇介绍 前些天自己在整理 SSIS 2012 资料的时候发现了一个功能设计上的疑似Bug,在 Script Task 中是可以给只读列表中的变量赋值.我记得以前在 2008 的版本中为了弄明白这个配 ...

  3. c语言怎么倒计时,如何在c语言程序中插入一个倒计时命令?

    C语言中提供了许多库函数来实现计时功能,下面是一些常用的计时函数: 1. time() 头文件:time.h 函数原型:time_t time(time_t * timer) 功能:返回以格林尼治时间 ...

  4. C语言字符串中运算符,c语言字符串中找到一个运算符,怎样实现运算

    1.一个字符串里面包含运算符,要转成正常运算的运算符,可以用 宏指令.相当于直接执行语句.宏指令在不同语言中执行方式不同的. 2.例程: //基本的堆栈思想 #include #include typ ...

  5. 测试工作中发现一个bug,而开发人员说不是一个bug,你该怎么处理?

    说法一: 1.首先明确开发说不是bug的理由. 2.如果是需求变更, 那就找产品经理确认是否是需求变更. 3.如果开发说测试环境问题, 让他说明清楚测试环境问题是什么,按照他说的验证一遍, 如果确实如 ...

  6. Go 程序设计语言书中 源码

    Go 程序设计语言源码: https://github.com/Mountains-and-rivers/gopl.io

  7. [原]发现QQLive中的一个bug

    使用IE8浏览器的用户发现QQLive右侧视频首页一片空白,后来把该页的地址(http://cache.tv.qq.com/v8/index.htm)提交到IE8下一看,也是无法显示,最后把该页保存下 ...

  8. 《致加西亚的信》一书中的一个隐蔽错误

    来源:blog,csdn,net/clever101 作者:朱金灿 <致加西亚的信>是一本著名的励志书籍.我手头上有一本哈尔滨出版社的.该书中有一篇由<致加西亚的信>的作者阿尔 ...

  9. tensorflow代码中的一个bug

    tensorflow-gpu版本号 pip show tensorflow-gpu Name: tensorflow-gpu Version: 1.11.0 Summary: TensorFlow i ...

最新文章

  1. NameError: name ‘sklearn‘ is not defined的解决方法:
  2. CNN模型 INT8 量化实现方式(一)
  3. ThreadLocal怎么实现线程隔离的?可见性问题?为什么要重新定义一个threadLocalHashCode?为什么有内存泄露?弱引用又是什么?
  4. 原生JAVA的TCP/UDP编程
  5. WNEWS 专题系统
  6. 在 ASP.NET Core 项目中使用 AutoMapper 进行实体映射
  7. 666! 玩王者,识英雄,这样也能上顶会!
  8. 什么是系统架构设计:关于架构演进理论
  9. 【解决方案】pytorch中loss变成了nan | 神经网络输出nan | MSE 梯度爆炸/梯度消失
  10. js选中文字兼容性解决
  11. Eclipse的一些常用的快捷键
  12. 第八章 虚拟机字节码执行引擎
  13. android框架xUtils使用介绍
  14. java 线程优先级_Java线程优先级
  15. 沪深300ETF基金与其业绩比较基准差别的原因
  16. start request repeated too quickly for filebeat.service
  17. MSBI表格模型与多维模型比较
  18. xiunobbs装插件
  19. 周鸿祎谈5G时代网络安全:手机病毒可能会更猖狂
  20. RIoTBoard开发板系列笔记(三)—— 移植Gstreamer

热门文章

  1. 头文件和实现文件的关系
  2. 将Access数据库导入到SQLite最简单最实用的方法 -转
  3. 蓝桥杯 ALGO-159 算法训练 P0103
  4. [Java] 蓝桥杯BASIC-27 基础练习 2n皇后问题
  5. html阶梯统计,html,_有什么图表可以显示阶梯费率,html - phpStudy
  6. php的4种常用运行方式
  7. git 远程代码回滚master
  8. Spring源码总结与分析
  9. 分布式系统事务一致性解决方案(转)
  10. 数据结构_二叉树非递归遍历