《C陷阱与缺陷》读书笔记

《C缺陷与陷阱》读后感-0     为找工作,前段时间把C语言仔细温习了遍,还草草地看了遍《程序员面试宝典》,加之毕业设计中写了些自以为值得称赞的程序,以为自己对C语言已经有了良好的把握。不过,在刚刚看了两章《C缺陷与陷阱》后,才发现自己的认识是多么的肤浅,才发现C语言的高深莫测,也更加加深了这样的理念:任何事情都有不断深入的必要和要求。同时,为了加深认识,也为练习文字能力,现将主要认识总结如下。    1.C语言是人与 阅读详情
  1. 在C语言中,符号中间的空白(包括空格符,制表符和换行符)将被忽略。

  2. 贪心法:C语言中,每一个符号应该包含尽可能多的字符。

  3. 如果一个整形常量的第一个字符为0,那么该常量将被视为八进制数。

  4. 用单引号引起的一个字符实际上代表一个整数,整数值对应于该字符在编译器所采用的字符集中的序列值;而用双引号引起的字符串,代表的却是一个指向无名数组起始字符的指针,该数组被双引号中的字符以及一个额外的二进制为0的字符'\0'初始化。

  5. !=的优先级比&高,加法运算符优先级比移位运算符高。

  6. 优先级表:


  7. 优先级助记:

    1. 优先级最高的并不是真正意义上的运算符,包括数组下标,函数调用操作符,结构成员选择操作符。他们都是自左至右结合。

    2. 单目运算符的优先级仅次于前者,在所有真正意义上的运算符中,他们的优先级最高。类型转换也是单目运算符。他们自右至左结合。接下来是双目运算符,其中,算术运算符优先级最高,移位运算符次之,关系运算符再次之,接着是逻辑运算符,赋值运算符,最后是条件运算符。

    3. 我们需要记住的最重要两点是:

      1. 任何一个逻辑运算符的优先级低于任何一个关系运算符。

      2. 移位运算符优先级比算术运算符低,但比关系运算符高。

  8. 任何两个逻辑运算符都具有不同的优先级,所有按位运算符优先级要比顺序运算符高,每个“与”运算符要比相应的“或”高,二按位异或介于按位与和按位或之间。

  9. 注意不要在if或while语句后面写一个分号,如果要写,请用大括号括起来。实际上,这也是我们提倡的一种编程风格。

  10. C语言要求,在函数调用时即使函数不带参数,也应包括参数列表。因此,如果f是一个函数,f()时一个函数调用语句,而f是一个什么也不做的语句,更精确的说,它计算函数f的地址,却并不调用该函数。

  11. 悬挂else问题的解决方法:else总是与同一括号内最近的未匹配的if结合。

  12. C语言中只有一维数组,而且数组大小在编译时就作为一个常数确定下来。然而,数组元素可以是任何类型的对象,当然也可以是另外一个数组。

  13. 对于一个数组,我们只能做两件事:确定数组大小,以及获得指向该数组下标为0元素的指针。其他对数组的一切操作,都是通过指针来进行的。换句话说,任何一个数组下标运算都等同于一个对应的指针运算。

  14. 对于int ar[12][13],说明ar数组拥有12个数组类型的元素,其中每个元素都是拥有13个整型元素的数组。(而不是反过来的),因此,sizeof(ar)的值是12*13*sizeof(int)。

  15. 对于除sizeof之外的其他场合,ar总被解释为指向数组起始元素的指针。

  16. 对于int ar[12];,&ar是一个指向数组的指针,而a是指向数组首元素的指针。

  17. eg:int *p;,对指针的声明解释方式应该是*p是一个整型值,所以p就是一个指向整型元素的指针。

  18. 由于栈顶在内存中处于低地址空间,栈底处于高地址空间,故数组在入栈时是从后往前的(也就是由下标大的值依次往下标小的值压栈)


  19. C语言中,字符串常量代表了一块包括字符串中所有字符以及一个空字符('\0')的内存区域的地址。

  20. malloc函数可能无法开辟足够的空间,因此可能返回空指针。然而,即使开辟成功,也应在使用完毕后及时释放该空间。

  21. 在字符串拷贝时,新开辟的空间大小往往是strlen(s)+1。

  22. C语言无法将数组作为参数传递给一个函数。如果我们使用数组名作为参数,它会被转换为指向数组第一个元素的指针。但其他情况下不会这样转换,比如:externchar hello[];和externchar*hello;

  23. C语言中将一个常数转换为一个指针,得到的结果取决于具体的C编译器。但有一个例外,就是0。编译器保证由0转换而来的指针不等于任何有效的指针。处于代码文档化的考虑,常数0经常用一个符号来代替:#define NULL 0。

  24. 将0转化为指针使用时,该指针绝对不能解除引用(dereference)。

  25. 避免“栏杆错误”的原则:

    1. 首先考虑最简单情况下的特例,然后将得到的结果外推。

    2. 仔细计算边界,绝不掉以轻心。

    3. 或者将栏杆的边界设为左闭右开区间(直接相减,结果不用加一,即不对称边界)。

  26. 求值顺序:和运算符的优先级不是一回事。典型的运算符有&&(若左边为假,则不会对右边求值),||(和&&一样,先对左侧求值,只在需要时才对右侧操作数求值),?:(eg:a:b?c;先对a求值,再根据a的值决定对b还是c进行求值),,(逗号,先对左侧求值,然后该值被丢弃,再对右侧操作数求值)。实际上,C语言只有这四种运算符存在规定的求值顺序,其他运算符对其操作数的求值顺序是未定义的。

  27. 承上,要说明的是,分隔函数参数的逗号并非是逗号运算符。例如,函数f需要两个参数,则f(x,y);的求值顺序是未定义的;而函数g只需要一个参数,则g(x,y)先对x求值,然后将其丢弃,再对y求值。特别地,复制运算符并不保证任何求值顺序。

  28. 关于整数运算:无符号数没有“溢出”之说,因为无符号数是以2的n次方为模(n是结果中的二进制位数)。如果一个有符号数和一个无符号数进行运算,有符号数会被转换为无符号数,所以也不会溢出。

  29. main函数如果不写返回值,默认为int。一个返回值为整型的函数如果返回失败,实际上隐式地返回了某个“垃圾”整数,只要该值不被用到,就无关紧要。但有些情况下对于main的返回值却并非如此,大多数C语言实现都通过main返回值来告知操作系统该操作是成功还是失败。典型的处理方案是,返回值为0代表执行成功,非0代表失败。如果该程序被别的程序调用,且main没有返回值,那么有可能看上去执行失败,得到令人惊讶的结果。

  30. 许多系统中连接器是独立于C语言实现的,且与C编译器分离,它不可能了解C语言的诸多细节。但它能够理解机器语言和内存布局。C编译器有责任以适当的方式通知连接器,确保未指定初始值的外部变量初始化为0。

  31. static定义的变量(或函数)的作用域值局限于本文件内,其他文件是不可见的。

  32. 如果一个函数在被定义或声明之前被调用,那么他的返回值类型默认为整型,但这往往会得出错误的结果。C语言的规则是,如果一个未声明的标示符后面跟了一个开括号,那么它被视为一个返回整型的函数。

  33. 如果一个函数的参数中没有float,short或char类型的参数,在声明中可以省略其参数类型的说明。

  34. 如果在一个源文件中定义一个变量,在另一个源文件中用external声明它,则他们的类型必须相同(这是程序员的责任)。尤其注意,不要定义为char name[];而声明为char *name;

  35. 对于char c; (c=getchar())!=EOF;c被声明为char类型,而不是int类型,这意味着,c无法容纳所有可能的字符,特别是,可能无法容纳EOF。一种可能是,某些合法的字符被“截断”后使得c的值与EOF相同;另一种可能是,c根本无法取得EOF的值。对于前一种情况,文件将在复制的中途终止;对于后一种情况,程序将陷入死循环。但实际上,可能还有第三种情况,就是编译器直接在while中比较getchar()的返回值和EOF,而不是将c拿来比较,这样的话,程序看起来“似乎”能够正确运行。

  36. 对文件的读写:为了保持与过去不能同时进行读写操作的程序向下兼容性,一个输入操作后不能直接紧跟一个输出操作,反之亦然。如果要同时进行输入和输出,必须在其中插入fseek()函数的调用。

  37. 所有的C语言实现中都包括有signal()库函数,作为捕获异步事件的一种方式。(要使用它,需引入signal.h头文件)

  38. 因为函数调用有一定的开销,所以将一些小的函数定义为宏,可以提高运行时效率。但定义宏时,要确保其中的参数没有副作用,并且为每一个参数加上括号。

  39. 不能忽视宏中的空格;宏并不是语句;宏并不是函数;宏并不是类型定义;

  40. 对于标示符的规定,ANSIC所能保证的只是,C语言必须能够区别出前6个字符不同的外部名称,并不区分字母的大小写。因此,若两个函数的名称为print_fields和print_float,或者State和STATE,这样的命名就不恰当。

  41. C语言的定义中对3种不同类型整数的相对长度做了一些规定(short,int,long):

    1. 3种类型的整数其长度是非递减的;

    2. 一个普通整数(int)足够大以容纳任何数组下标;

    3. 字符长度由硬件特性决定。

  42. 如果c是一个字符变量,想用(insigned)c将其转化为无符号整数,这时会失败的。因为在字符c转化为无符号整数时,c首先会被转化为int型整数,而此时可能得到非预期的结果。正确的方式是(insigned char)c,因为unsigned char类型的字符在转化为无符号整数是无需转化为int型整数,而是直接进行转化。

  43. 对于移位运算符:向右移位时,如果被移位的对象是无符号数,那么空出的为将被0填充;若是有符号数,则既可用0填充(逻辑移位),也可用符号位填充(算数移位)。

  44. 移位计数允许的取值范围是0~n(n是该变量的二进制位数),即大于等于0,而小于n。因此,不可能在单次操作中将某个数的所有位都移出。为什么要有这个限制呢?原因是只要加上了这个限制,我们就能在硬件上高效的实现移位运算。

  45. 移位运算符的效率要比除法高效的多。但即使C实现将符号位复制到空出的位中,有符号整数的向右移位也不等同于除以2的某次幂。证明:(-1)>>1,这个操作结果一般不可能为0,但(-1)/2在大多数C实现上结果都是0。

  46. 内存位置0:NULL指针不指向任何对象。因此,除非是用于赋值或比较运算,出于其他任何目的使用NULL指针都是非法的。

  47. 除法运算时发生的截断:假定我们让q=a/b;r=a%b;(假定b大于0)。我们希望a,b,q,r之间维持的关系是:

    1. 最重要的一点:我们希望q*b+r==a,因为这是余数的定义。

    2. 如果我们改变a的符号,我们希望改变q的符号,但不会改变其绝对值。

    3. 当b>0时,我们希望保证r>=0且r<b。
      但是很不幸,以上三条无法同时成立(可以自行验证)。因此C语言(或其他语言)在实现除法时,必须放弃其中的至少一条,大多数程序设计语言选择放弃第3条,而改为余数与被除数的正负号相同。然而,C语言的定义只保证了性质1,以及当a>=0且b>0时,保证|r|<|b|以及r>=0。

  48. rand函数有两个版本,分别是VAX-11(返回值范围为0~231-1)和AT&T(返回值范围为0~215-1)。如果我们用到了rand函数,就必须根据特定的C语言实现做出“剪裁”。ANSCI标准中定义了一个常数RAND_MAX,它的值等于随机数的最大取值。

  49. 在一个负数前加上-转化为整数有可能溢出。

  50. 建议

    1. 在编写程序时,考查最简单的特例。比如当部分输入数据为空或只有一个元素时。

    2. 使用不对称边界。例如数组的下标。

    3. 进行预防性编程。
      <完>


另:可以关注我的微信公众号:Smart

论Go语言中指针数组和数组指针的不同 前面已经和大家详细的介绍了指针的用法,那么所谓的指针数组和数组指针到底有何变化,之间有什么联系呢?是否表示一个意思,还是有不同含义,下面就聊聊。 指针数组 首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身的大小决定,每一个元素都是一个指针,在32 位系统下任何类型的指针永远是占4 个字节。它是“储存指针的数组”的简称。 数组指针 首先它是一个指针,它指向一个数组。在32 位系统下任何类型的指针永远是占4 个字节,至于它指向的数组占多少字节,不知道,具体要看数组大小。它是“指向数组的指针”的简 阅读详情

相关推荐

VMware虚拟机的安装教程

VMware 虚拟机的备份与恢复是保障数据安全和业务连续性的重要措施。综上所述,VMware 虚拟机的备份与恢复策略有多种选择,企业和用户可以根据实际需求和资源情况选择适合自己的方案,以确保虚拟机数据的安全和业务的连续性。

huanghm88的专栏 2950

C语言进阶:C陷阱与缺陷(读书笔记总)

C陷阱与缺陷读书笔记,C语言进阶

嵌入式小师兄的博客 4267

Mac终端SSH连接腾讯云服务器保姆级教程(附秘钥管理技巧)

本文提供Mac终端SSH连接腾讯云服务器的详细教程,涵盖密钥生成、权限设置、连接优化及高级管理技巧。通过清晰的步骤和实用配置,帮助用户安全高效地管理远程服务器连接,特别适合开发者和运维人员参考。

weixin_29248313的博客 455

c语言缺陷与陷阱,《C语言的缺陷与陷阱》读后总结

我读的这本书是Andrew Koneig 著作的。读完了之后,对我对c语言的理解增加了很多,总结于此,以备我以后或者其他读者学习。第一章:词法陷阱1、编译程序编译C程序的时候使用的是贪心法,也就是说编译程序讲程序分解成符号的方法是,从左到右一个字符一个字符的读入,如果字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串师父可能是一个符号的组成部分,如果可能,继续读入下一个...

weixin_34738099的博客 771

零基础实战:YOLO检测头自定义替换全攻略

本文为零基础用户提供了YOLO检测头自定义替换的完整实战指南。通过将检测头比作汽车的“方向盘”,文章详细阐述了为何需要替换、如何寻找和集成新检测头模块、修改配置文件以及最终训练验证的全过程,旨在帮助用户针对特定任务(如小目标检测)提升模型性能。

perl8的博客 255

液态神经网络(LNN):打破AI“静态快照”的连续动力学革命---AI大模型系统从零开始0029

MIT研究团队受秀丽隐杆线虫神经系统的启发,开发出革命性的液态神经网络(LNN)。该技术通过连续微分方程建模神经元动态,实现输入响应速度的自适应调节,解决了传统AI模型静态化、高能耗和低解释性的痛点。LNN具有三大突破性优势:仅需少量神经元(如20个)即可完成复杂任务;能处理非均匀时序数据;在自动驾驶、医疗监测等领域展现出卓越的适应性和鲁棒性。这项将生物智能与数学建模完美融合的技术,有望成为下一代AI的核心架构,目前已在无人机导航等场景验证了其高效性,被预测为2026年最具潜力的AI突破方向。

添柴程序猿的专栏 372

读完《C 陷阱与缺陷》感

读完《C 陷阱与缺陷》感o1书并不厚,一百多页。昨天终于抽出一下午的时间在图书馆把剩下的一半看完,虽只是第一遍,但还是有些感想。02C 强大的灵活性导致了任何一个C 代码都可能隐藏着难以察觉的深层次的错误,而往往越难以发掘的错误所带来的后果往往更加严重,甚至是系统级别的灾难性后果!C语言标准中的各种语法规则简短而简单,但是当它们放到一起,组成一句...

通用代码技术 320

[QMT量化交易小白入门]-七十六、从tick数据中获取高频交易的量价背离信号

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。

木头大左的博客 790

《c陷阱与缺陷》读书笔记

1. = 不同于 == 2. & 和 | 不同于 && 和 || 3. 编译器将程序分解成符号的方法是,从左到右一个一个读,直到读入的字符组成的字符串已不在可能组成一个有意义的符号,贪心的处理程序。如a --- b编译器就会认为是  a-- - b,而不是认为a - --b。 4. 整数常量,如果一个整型常量第一个字符是0,那么该变量会被认为是8进制数。 5. 单引号引起的一个字符实际上代

京东放养的爬虫 1469

Python爬虫实战:股票历史数据抓取与量化回测全流程详解

我们以**东方财富网(eastmoney.com)和雪球网(xueqiu.com)**为主要目标,演示如何爬取A股历史行情。最常用的HTTP请求库,简单易用,适合静态页面数据请求。本文详细介绍了从股票历史数据抓取到简单回测的完整流程,代码示例基于最新技术,结构清晰,适合初学者和进阶者学习量化投资实战。希望对你入门Python爬虫和量化交易有所帮助!

2201_76125261的博客 1778

Megatron-LM从头训练大语言模型:并行策略图示【Tensor并行、Pipeline并行、Data并行、Sequence并行、virtual_pipeline并行、Context并行】

节点包含的层每GPU的参数内存每GPU的激活内存节点0Stage 0层1-1212层参数/2 (TP切分)8k序列激活 (CP切分)节点1Stage 1层13-2412层参数/2 (TP切分)8k序列激活 (CP切分)节点2Stage 2层25-3612层参数/2 (TP切分)8k序列激活 (CP切分)节点3Stage 3层37-4812层参数/2 (TP切分)8k序列激活 (CP切分)负载均衡:每个节点处理相同数量的层(12层)内存优化。

u013250861的博客 285

C陷阱与缺陷读书笔记

《C》

doodlesomething 758

STM32+FreeRTOS环境下LwIP协议栈移植详解

本文详细介绍了在STM32F407ZGT6平台上移植轻量级TCP/IP协议栈LwIP的过程。使用FreeRTOS操作系统和LAN8720A以太网PHY芯片,通过STM32CubeMX生成基础工程配置。重点包括LwIP源码的获取与工程集成、关键配置文件的编写(如lwipopts.h)、操作系统适配层sys_arch.c的实现,以及以太网接口驱动ethernetif.c的移植。文章特别强调内存管理、中断优先级、硬件校验和等关键配置项的注意事项,为基于STM32和LwIP的嵌入式网络开发提供了实用参考。

电脑管家 753

《C陷阱与缺陷》读书笔记(一)

这个代码中误将“==”写成了“=”,导致最开始是为c赋值为空字符串,那这行语句恒为真,所以“||”运算符有一个短路现象,它就不会向下执行,也就不会判断c是否等于“\t”和“\n”了。上面代码本意是判断x和y是否相等,如果它们相等,就跳出循环,但是却将“==”误写成了“=”,这样一来if条件判断语句永远为真(赋值语句的结果恒为真),所以就会跳出循环,没有判断x和y相等这一过程。“&”可以翻译为“and”,“|”可以翻译为“or”,所以它们表示的是二进制的按位与和按位或。或者还可以将“==”判断改成“!

m0_68190153的博客 689

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

《C缺陷与陷阱》读书笔记

最近因为工作需要开始重新拾起C语言,虽然说基本语法什么的没有太大问题(不行就网上搜索),但复习巩固下C语言也是不错的。正好身边有《C缺陷与陷阱》这本书,于是就有了这篇读书笔记。

RdouTyping的博客 342

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【读书笔记】C陷阱和缺陷

文章目录第一章 词法“陷阱”1.1 = 不同于==1.2 &和| 不同于 &&和||1.3语法分析中的“贪心法”1.4整形常量1.5字符与字符串第二章 语法陷阱2.1 理解函数声明2.2运算符优先级问题2.3注意作为语句结束标志的分号2.4 switch语句2.5 函数调用2.6“悬挂”else引发的问题第三章 语义“陷阱”3.1 指针与数组数组指针数组名与指针引用二维数组二维数组与指针3.2 非数组的指针3.3作为参数的数组声明3.4 避免”举ou法“ 第一章 词法“陷阱” 1.1

weixin_42881419的博客 1066

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

C陷阱与缺陷 —— 读书笔记-1、词法“陷阱”

《C陷阱与缺陷》是由Andrew Koenig所著,高巍译。Andrew Koenig是AT&T大规模程序研发部(前贝尔实验室)成员,不仅有着多年的C++开发,研究和教学经验,而且还亲身参与了C++的演化和变革,对C++的变化和发展起到重要的影响。 第一章    词法陷阱 编译器中负责将程序分解为一个一个符号的部分,一般称为“语法分析器”。 1.1

Cawen的技术博客 813

《C陷阱与缺陷》读书笔记与总结

《C陷阱与缺陷》读书笔记 目录《C陷阱与缺陷》读书笔记一,函数指针和指针函数二,C语言数组三,空指针并非空字符串四,整数溢出五,为main函数提供返回值六,声明和定义(extern)七,命名冲突与 static修饰符八,形参、实参和返回值九, 检查外部变量类型十,预处理器-不能忽视宏定义中的空格十一,预处理器-宏不是函数十二,宏不是类型定义十三,比较时把常量写在左边 ​ 一,函数指针和指针函数 float *g() , (*h)(); ()的优先级大于 * , 因此 *g() 为 *( g() ) ,该函

DayDayUp 1万+

C陷阱与缺陷-- 读书笔记一

<br /><br />                     C陷阱与缺陷<br />                                                        读书笔记一<br />1.       词法“陷阱”<br />1.1   =不同于= =<br />C语言中用字符更少“=”来表示频繁发生和使用的赋值操作。而用“= =”表示使用相对较少的比较操作。由于两者相近,可能会因为失误将“= =”误输入为“=”。或反之的误输入。造成程序的不正常,增加程序员工作。

ts_54eagle的专栏 701
上一篇: 计算机经典书籍电子书合集(适合计算机学生学习以及程序员笔试、面试)
下一篇: 《高质量的C/C++编程指南》读书笔记
SmartBrave
博客等级 码龄12年 25粉丝 69原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值