第七十二天学习记录:初读《C陷阱与缺陷》

news/2024/11/24 5:43:16/

首次快速阅读完《C陷阱与缺陷》,感觉还是读得有些稀里糊涂的。
首先给人的感觉就是大部分人可以感受到的,作者对于较为初代C语言的研究已经达到了可以说是“炉火纯青”的程度。
尽管作者写这本书的时候距离至今已经过去了二十几年,但很多C语言所存在的缺陷以及作者的思想至今都适用。
与大部分书类似,该书也是由浅入深,由易到难的方式切入。
从相对简单的“=与==”不同开始,到后面让我看不懂到抓狂的可移植性缺陷。

下面列举些书中有意思的问题:

栏杆问题

这个问题个人觉得可以说是很经典的。也许作为程序员,C和C++数组或者说很多情况下标从0开始已经深入骨髓,但作者却通过一个很现实的情况对“下标”做了很恰当的“比喻”。
修建一个100英尺长的护栏,护栏的栏杆之间相距10英尺,你需要多少根栏杆。
答案是11根。
作者在这里由这个实例引用了边界计算与不对称边界。在所有常见的程序设计错误中,最难于察觉的一类就是“栏杆错误”。
为了避免这个错误有两个通用原则:
(1)、首先考虑最简单情况下的特例,然后将得到的结果外推。
(2)、仔细计算边界。

a+++++b

在初学C语言后,尤其是在学习了运算优先级后,很容易将这句代码理解为:a++ + ++b,但是,根据“贪心法”的规则,上式会被分解成:
a++ ++ +b
这个式子从语法上来说是不正确的。

当一个程序异常终止时

当一个程序异常终止时,程序输出的最后几行常常会丢失,原因是什么?我们能够采取怎样的措施来解决这问题?
setbuf(stdout,(char*)0);
这个语句必须在任何输出被写入到stdout(包括任何对printf函数的调用)之前执行。该语句最恰当的位置就是作为main函数的第一个语句。

除法运算时发生的截断

假设让a除以b,商为q,余数为r:
q=a/b;
r=a%b;
假设b>0。
从逻辑上讲,我们希望a,b,q,r之间维持如下关系。
1、最重要的一点,我们希望q*b+r==a,因为这是定义余数的关系,如果这个都不维持,数学会抓狂的。
2、如果我们改变a 的正负号,我们希望这会改变q的符号,但这不会改变q 的绝对值。
3、当b>0时,我们希望保证r>=0且r<b。例如,如果余数用于哈希表的索引,确保它是一个有效的索引值很重要。
这三条性质是我们认为整数除法和余数操作所应该具备的。但不幸的是,它们不可能同时成立。
考虑一个简单的例子:3/2,商为1,余数也为1 。此时,第一条性质得到了满足。(-3)/2的值应该是多少呢?如果要满足第二条性质,答案应该是-1 ,但如果是这样,余数就必定是-1,这样第三条性质就无法满足了。如果我们首先满足第三条性质,即余数是1,这种情况下根据第一条性质则商是-2,那第二条性质又无法满足了。
因此,C语言或者其他语言在实现整数除法截断运算时,必须放弃上述三条原则中的至少一条。大多数程序设计语言选择放弃第三条,而改为要求余数与被除数的正负号相同。这样,性质1和性质2就可以得到满足。大多数C编译器在实践中也都是这样做的。
然而,C语言的定义只保证了性质1,以及当a>=0且b>0时,保证|r|<|b|以及r>=0。后面部分的保证与性质2或者性质3比较起来,限制性要弱得多。

在数学上,我们可以将一个整数a除以一个非零整数b,得出两个整数c和d,使得

a = b * c + d

其中c是商,d是余数。如果a<0,那么我们可以将a表示为
a = -(-a)
因此,我们可以重写上述公式,得到:

-a = b * (-c) + d

也就是说,当a<0时,余数d的符号与b相反,即为-b或者-b的绝对值中的一个。
类似的,如果b<0,我们也可以用类似的方式来求余数d。如果a和b都小于0,就需要将上述两种情况进行合并。此时,可以先将a和b都乘以-1,之后按照以上方法得出余数,然后再将余数乘以-1得到正确的结果。
需要注意的是,在实际编程中,C++中有两个函数可以求解除法的商和余数,分别是divstd::div.它们的返回值是一个结构体,包含商和余数两个成员:c = div(a,b).quotd = div(a,b).rem。此外,关于负数除法运算的详细请参考C++标准中[N3337]§5.6.4和expr.multip。
举例:

int main()
{int a, b, q, r;a = -3;b = -2;q = a / b;r = a % b;printf("%d %d\n", q, r);return 0;
}

输出:1,-1

int main()
{int a, b, q, r;a = -3;b = 2;q = a / b;r = a % b;printf("%d %d\n", q, r);return 0;
}

输出:-1,-1

int main()
{int a, b, q, r;a = 3;b = -2;q = a / b;r = a % b;printf("%d %d\n", q, r);return 0;
}

输出:-1,1


http://www.ppmy.cn/news/361586.html

相关文章

可能是知乎里最浅显易懂的激光测距技术讲解:什么是点激光,线激光,面激光。它们在扫地机器人上是如何应用的。

几年前的行业内人士肯定很难想到,在不久后的今天激光测距这项技术会距离生活这么近,甚至直接深入到我们家里天天使用。 激光测距行业努力了这么多年发展的技术几乎全都用上了,就为了给扫地机器人检测它前面有没有狗屎。。。 虽然扫地机器人上用上这些技术有一两年了,但是…

STM32FreeRTOS操作系统移植

移植好的FreeRTOS模板&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1_87VQAWXUl4jTqSCZ0MFjw?pwddw52 提取码&#xff1a;dw52 1.在工程中新建FreeRTOS文件夹 2.把源码source里面的文件全部粘贴进FreeRTOS文件夹中 3.在portable文件中只保留一下文件&#xff0c;…

安卓代码中@string什么意思

在 Android 开发中&#xff0c;string 是一个资源类型&#xff0c;表示字符串资源。通过定义字符串资源&#xff0c;我们可以将应用程序中使用的字符串单独提取出来&#xff0c;方便进行统一管理和维护。 在 Android 应用程序中&#xff0c;我们通常会将字符串定义在 res/valu…

NDM下载

NDM下载&#xff1a; http://www.neatdownloadmanager.com/index.php/en/

mhdd测试硬盘软件,mhdd硬盘检测工具

不知道怎么回事&#xff0c;小编的机器硬盘老是咯吱咯吱的响&#xff0c;使用mhdd硬盘检测工具检查了一下&#xff0c;发现硬盘有坏道。。用工具修复一下硬盘还能使用下子。。 功能&#xff1a; 修复成功率(1类坏道百分之九十以上&#xff0c;2类坏道百分之七十&#xff0c;3类…

mhdd硬盘测试软件,mhdd硬盘检测工具使用攻略 mhdd硬盘检测工具如何使用

mhdd硬盘检测工具是一款十分好用的软件&#xff0c;相比于市面上的其它同类软件相比&#xff0c;这款软件最大的优势就在于扫描速度十分迅速&#xff0c;因此&#xff0c;用户在对其进行使用的同时&#xff0c;也不需要花费掉过多的时间。那么&#xff0c;mhdd硬盘检测工具如何…

MHDD教程,硬盘维修方法

MHDD工具说明&#xff1a; 1、MHDD是俄罗斯Maysoft公司出品的专业硬盘工具软件&#xff0c;具有很多其他硬盘工具软件所无法比拟的强大功能&#xff0c;它分为免费版和收费的完整版&#xff0c;本文介绍的是免费版的详细用法。这是一个G表级的软件&#xff0c;他将扫描到的坏道…

制作MHDD启动U盘

拿到一块硬盘需要修复&#xff0c;准备使用DOS版的MHDD&#xff0c;需要制作启动U盘&#xff0c;步骤如下&#xff1a; 1. 下载MHDD软件的镜像&#xff08;iso文件&#xff09; https://download.csdn.net/download/zhouyingge1104/12228783 2. 下载烧录工具&#xff0c;例如…