程序人生 | 我的《C陷阱与缺陷》读书笔记

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

本文首发于 2014-08-04 17:56:55

第一章 词法“陷阱”

1. =不同于==

if(x = y)
         break;

实际上是将y赋给x,再检查x是否为0。

如果真的是这样预期,那么应该改为:

if((x = y) != 0)
         break;

2. &和| 不同于 && 和 ||

3. 词法分析中的“贪心法”

编译器将程序分解成符号的方法是:从左到有一个一个字符的读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符床是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号。例如:

y = x/*p; 会被解析为:/* 注释符号

4. 整型常量

010(八进制数) 不同于 10(十进制)。

5. 字符与字符串

首先是单引号与双引号的区别:

  • 用单引号括起来的一个字符表示一个整数(ASCII码),而双引号括起来表示一个指针。

第二章 语法“陷阱”

1. 理解函数声明

弄懂(*(void(*)())0)(); //首地址为0的函数。

float (*h)(): h是一个指向返回值为浮点型的函数的指针

所以,(float (*)()) 表示一个“指向返回值为浮点型的函数的指针”的类型转换符。

fp(): 是(*fp)( )的简写。

*fp(): 是 *( (*fp) ( ) )的简写。

( *0 )( );

虽然上式编译器不认,但可以把0转换为指向“返回值为void的”函数的指针,所以0可变为: ( void(*) ( ) ) 0 ,代入(*0)(),得到:

(*( void(*) ( ) ) 0) ( )

该式子用等价于:

typedef void  ( *func ) ( );
( *( func ) 0 ) ( );

类似的,signal.h中对signal函数的声明:

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

2. 运算符优先级的问题

优先级运算符名称或含义使用形式结合方向说明
1[]数组下标数组名[常量表达式]左到右
1()圆括号(表达式) 函数名(形参表)左到右
1.成员选择(对象)对象.成员名左到右
1->成员选择(指针)对象指针->成员名左到右
2-负号运算符-表达式右到左单目运算符
2(类型)强制类型转换(数据类型)表达式右到左
2++自增运算符++变量名 变量名++右到左单目运算符
2–自减运算符–变量名 变量名–右到左单目运算符
2*取值运算符*指针变量右到左单目运算符
2&取地址运算符&变量名右到左单目运算符
2!逻辑非运算符!表达式右到左单目运算符
2~按位取反运算符~表达式右到左单目运算符
2sizeof长度运算符sizeof(表达式)右到左
3/除表达式 / 表达式左到右双目运算符
3*乘表达式*表达式左到右双目运算符
3%余数(取模)整型表达式%整型表达式左到右双目运算符
4+加表达式+表达式左到右双目运算符
4-减表达式-表达式左到右双目运算符
5<<左移变量<<表达式左到右双目运算符
5>>右移变量>>表达式左到右双目运算符
6>大于表达式>表达式左到右双目运算符
6>=大于等于表达式>=表达式左到右双目运算符
6<小于表达式<表达式左到右双目运算符
6<=小于等于表达式<=表达式左到右双目运算符
7==等于表达式==表达式左到右双目运算符
7!=不等于表达式!= 表达式左到右双目运算符
8&按位与表达式&表达式左到右双目运算符
9^按位异或表达式^表达式左到右双目运算符
10|按位或表达式|表达式左到右双目运算符
11&&逻辑与表达式&&表达式左到右双目运算符
12||逻辑或表达式||表达式左到右双目运算符
13?:条件运算符表达式1? 表达式2: 表达式3右到左三目运算符
14=赋值运算符变量=表达式右到左
14/=除后赋值变量/=表达式右到左
14*=乘后赋值变量*=表达式右到左
14%=取模后赋值变量%=表达式右到左
14+=加后赋值变量+=表达式右到左
14-=减后赋值变量-=表达式右到左
14<<=左移后赋值变量<<=表达式右到左
14>>=右移后赋值变量>>=表达式右到左
14&=按位与后赋值变量&=表达式右到左
14^=按位异或后赋值变量^=表达式右到左
14|=按位或后赋值变量|=表达式右到左
15,逗号运算符表达式,表达式,…左到右

3. 其他

主要是别多写分号,switch别忘了break,别写空else分支。

第三章 语义“陷阱”

1. 指针与数组

struct {
    Int p[4];
    Double x;
}b[17];

int calendar[12][31];
int (*p)[31];
sizeof(calendar):12*31=372

calendar[0] // 指向该一维数组,对应*p
calendar[0][0]
......
calendar[0][30]
calendar[1] // 指向该一维数组,对应*(p+1)
calendar[1][0]
......
calendar[1][30]
......
......
......
calendar[11] // 指向该一维数组,对应*(p+11)
calendar[11][0]
......
calendar[11][30]

2. 内存分配

free(r);

用malloc显式分配的空间,不会再退出本函数后自动释放掉,而是会等程序员显式释放后才消失。

注意检查,malloc分配的内存可能失败。

C语言中会自动地将作为函数参数的数组声明转换为对应的指针声明,如:

int strlen(char s[ ]){ }等价于int strlen(char *s){ }
但在其他情形下不会自动转换,也就是说不等价,如:
extern char hello[ ];和extern char *hello;完全不同。

边界计算
自己实现一个memcpy函数:

void memcpy(char *dest, const char *source, int k)
{
    while( --k >= 0 )
        *dest++ = *source++;
}

重点是:操作时一定要知道操作数据的长度。

整数溢出

  • 两个有符号整数相加会发生溢出。
  • 两个无符号整数相加不会发生溢出。
  • 一个有符号和一个无符号整数相加,因为有符号被自动转换成无符号,所以也不会溢出。

第四章 连接

编译器一般每次只处理一个文件。编译器的责任是把C源程序翻译成对连接器有意义的形式。

许多系统中的连接器是独立于C语言实现的,因此如果链接时候错误原因是与C语言相关的,连接器无法判断错误原因。但连接器能够理解机器语言和内存布局。

典型的连接器把由汇编器或编译器生成的若干个目标模块,整合成一个被称为载入模块或可执行文件的实体。

连接器通常把目标模块看成是由一组外部对象组成的。每个外部对象代表着机器内存中的某个部分,并通过一个外部名称来识别。因此,程序中的每个函数和每个外部变量,如果没有被声明为static,就都是一个外部对象。static的不会与其它源程序文件中的同名函数或同名变量发生冲突。对于非satatic的函数或变量的名称冲突的解决办法将在后面讨论。

除了外部对象外,目标模块中还可能包括了对其他模块中的外部对象的引用,当连接器读入一个目标模块时,它必须解析出这些引用,并作出标记说明这些外部对象不再是未定义的。

连接器的输入是一组目标模块文件和库文件。输出是一个载入模块。

避免外部变量的函数的冲突和不一致等问题的办法:

每个外部对象只在一个头文件里声明,需要用到该外部对象的所有模块都应该包括这个头文件。
定义该外部对象的模块也应该包括这个头文件。

第五章 库函数

没什么好说的,就是apue的一些函数而已。

第六章 预处理器

宏定义:主要是理解宏不是函数,而是直接替换。

  1. 不能忽视宏定义中的空格:
#define f (x) ( (x)-1 ):因为f后面多了一个空格,所以f(x)代表(x) ( (x)-1 )
  1. 宏并不是函数,所以注意那些括号:
#define abs(x) ( ( (x) >= 0)?(x):-(x) )
#define max(a,b) ( (a)>(b)?(a):(b) )
  1. 宏并不是语句:
#define assert(e) if (!e) assert_error(__FILE__, __LINE__)
  1. 宏不是类型定义
  • 错误用法:
#define int_8_ int*
        int_8 a,b; //则a是指针,b是int型
  • 正确用法:应该用typedef
typedef int * int_8_;

第七章 可移植性缺陷

主要是:

  1. 应对C语言标准的变更;
  2. 标识符名称的限制;
  3. 整数的大小;
  4. 字符是有符号整数还是无符号整数;
  5. 移位运算符;
    1. 在向右移位时,空出的位是由0填充还是1,还是由符号位的副本填充?如果被移位对象是无符号数,那么由0填充;如果是有符号数,那么是0或符号位的副本。
    2. 移位操作的位数允许的取值范围是什么?如果被移位对象的长度是n位,那么移位计数必须大于或等于0,而严格小于n。
  6. 移植性需考虑的地方:
    1. 机器的字符表不同。
    2. 有的机器是one’s complement,有的机器是two’s complement的。基于2的补码的计算机,所允许表示的附属取值范围要大于正数取值范围,所以有时取负值的运算会导致溢出。
    3. 各机器对取模运算的定义不同。

第八章 惯用与答案

将惯用的c == '\t'写作'\t' == c。

一旦写错成=号,编译器就能检查出来。


欢迎关注我的微信公众号【数据库内核】:分享主流开源数据库和存储引擎相关技术。

标题网址
GitHubhttps://dbkernel.github.io
知乎https://www.zhihu.com/people/…
思否(SegmentFault)https://segmentfault.com/u/db…
掘金https://juejin.im/user/5e9d3e…
开源中国(oschina)https://my.oschina.net/dbkernel
博客园(cnblogs)https://www.cnblogs.com/dbkernel
论Go语言中指针数组和数组指针的不同 前面已经和大家详细的介绍了指针的用法,那么所谓的指针数组和数组指针到底有何变化,之间有什么联系呢?是否表示一个意思,还是有不同含义,下面就聊聊。 指针数组 首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身的大小决定,每一个元素都是一个指针,在32 位系统下任何类型的指针永远是占4 个字节。它是“储存指针的数组”的简称。 数组指针 首先它是一个指针,它指向一个数组。在32 位系统下任何类型的指针永远是占4 个字节,至于它指向的数组占多少字节,不知道,具体要看数组大小。它是“指向数组的指针”的简 阅读详情

相关推荐

AI目标排序工具:用结构化决策替代盲目努力

目标管理本质上是多维权重下的动态决策问题,其核心难点在于人类认知系统难以持续处理紧迫性、影响范围、资源状态与价值观契合度等非线性变量。传统时间管理方法依赖主观判断或静态标签(如四象限),易陷入优先级幻觉;而现代AI辅助工具的关键突破,在于将模糊意图转化为可量化、可校准、可验证的结构化输入流程。本文聚焦轻量级AI工具1st-things-1st,解析其‘结构化输入→权重自定义→场景化模型→冲突显性化’的设计逻辑,强调AI不替代思考,而是放大清醒——通过强制价值观排序、动态情境锚定和模板专用建模,帮助职场人、自

weixin_33863087的博客 427

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

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

嵌入式小师兄的博客 4267

DeepSeek AI生活升级指南:40种即刻提效的日常认知增强用法

大语言模型正从通用问答工具演进为嵌入工作流的认知增强系统。其核心在于超长上下文理解、高精度指令遵循与本地化语义建模三大能力,支撑起信息处理、知识内化、内容生成与效率优化等基础技术价值。在知识管理、教育辅助、职场办公、编程协作等高频场景中,用户可通过自然语言提问,实现毫秒级响应与可执行结果输出。本文聚焦DeepSeek R1/V2的实际工程落地,详解40种经实测验证的‘毛细血管级’用法,覆盖从文本预处理、原子化提问到结果交叉验证的完整实践链路,助力非技术用户真正将AI转化为生产力杠杆。

weixin_34160277的博客 415

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

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

weixin_34738099的博客 771

无人车路径规划方法汇总

无人车路径规划方法汇总

weixin_44380244的博客 2561

ANSYS Products19.1下载及安装教程

ANSYS Products19.1下载及安装破解教程 前言 ANSYS软件是美国ANSYS公司研制的大型通用有限元分析(FEA)软件,是世界范围内增长最快的计算机辅助工程(CAE)软件,能与多数计算机辅助设计(CAD,computer Aided design)软件接口,实现数据的共享和交换,如Creo, NASTRAN、Algor、I-DEAS、AutoCAD等。ansys project包括一整套的软件集合,它耦合了CFD模型的前处理,求解器和后处理所需要的相关软件,特比是它的workbench模块,

Mekeater的博客 2万+

读完《C 陷阱与缺陷》感

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

通用代码技术 321

音频功放电路大全

作为硬件工程师,特别是做纯粹模拟电路、应用于音频功放的工程师,对于A类,B类,AB类,D类,G类,H类,T类功放应该特别熟悉。大多数工程师或许只知道其中的一部分、或者知道大概,为了让更多的工程师掌握更加详尽的音频功放知识,下文对以上说的音频功放做详细的说明。 功放,顾名思义,就是功率放大的缩写。与电压或者电流放大来说,功放要求获得一定的、不失真的功率,一般在大信号状态下工作,因此,功放电路一般包含电压放大或者电流放大电路没有的特殊问题,具体表现在:①输出功率尽可能大;②通常在大信号状态下工作;③非线性失真突

ltqdxl的博客 6597

速通C语言第零站

自我介绍&&编程学习计划

qq_73329472的博客 476

房产平台系统小程序源码

🏠 一键解锁购房新体验 🔓房产小程序 实现前端 发布二手房 租房 商品 求租 求购等信息;后台发布 新房,二手房租房 商品 写字楼 求租求购等房源信息;功能完善的一块房产小程序。

2401_84413757的博客 796

【鼠标在不点击的情况下,直接移动到QT控件上不显示提示信息】

有时明明已经调用了setToolTips方法,鼠标移动到QT控件上仍然不会有提示信息,这时候就需要具体分析下。重点就是标红的这段话,大概意思就是。.h文件中加入鼠标移动事件的定义。.cpp文件中实现该事件。

ZTH_G的博客 2426

以后需要抽时间读,并且写读书笔记的书

Code: The Hidden Language of Computer Hardware and Software (《编码的奥秘》)Computer System: A Programmer’s Perspective (《深入理解计算机系统》) / Windows via C/C++ (《Windows核心编程》 / 《程序员的自我修养》Code Complete 2(《代码大全》)/ T

李奥 - 追梦赤子心 598

深度学习笔记(1)机器学习与深度学习基础

一些深度学习的简单概念和Transformer的学习。

hanliu2003的博客 1493

《C陷阱与缺陷》读后感

《C陷阱与缺陷》读后感 这本书我在亚马逊上买过一本,放在单位了。后来,想再读,于是在淘宝上又买了一本。 这本书很簿,但很有意思 讲了一些C的内幕,感觉很好玩的。 1.为什么C赋值是有=,而相等是用==呢? 因为赋值语句出现的机率大,所以象哈夫曼编码一样,出现机率大的码就短些,好玩吧。、 2.语句 y =x/*p /* int *p */ 这里p是指向整数的指针,那上面如何理解,是x/(*p)吗?...

woshiyilitongdouzi的博客 938

什么是 SAP ABAP AMDP?

SAP HANA是SAP开发的一种内存数据库管理系统,它具有出色的性能和处理大规模数据的能力。为了充分利用SAP HANA的性能,SAP引入了AMDP技术,以便将数据库操作推送到数据库服务器执行,从而减少数据传输和处理时间。AMDP方法通常需要输入参数和输出参数。输入参数用于传递数据到SQLScript代码,而输出参数用于接收SQLScript代码的结果数据。ENDMETHOD.ENDCLASS.我们定义了一个输入参数来传递销售订单数据,以及一个输出参数来接收计算结果。ENDMETHOD.

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 910

1、vectorCast单元测试常用操作

进入软件主页面,点击file,选择set working directory,随便选择一个保存该项目的目录即可。

weixin_59334478的博客 2158

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

词法分析的最基本原则是贪心法。和一些晦涩的函数签名的解析。

qq_39377889的博客 1314

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C陷阱与缺陷》的一些心得体会-----1

前言和导读   “得心应手的工具在初学时的困难程度往往超过那些容易上手的工具。”比较认同这句话。我至今觉得自己其实还是个刚入了门的初学者。   第一章  “词法”陷阱     由于之前学过编译原理,对编译器词法分析(主要是符号识别过程)比较了解,理解起来不困难。   在讲到"="和"=="、"|"和"||"、"&"和"&&"时,联想起以前见过一些程序中出现了类似

Vast_Sea的专栏 1332

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

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

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

DayDayUp 1万+

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

第0章 导读 第1章 词法“陷阱” 第2章 语法“陷阱” 第3章 语义 “陷阱” 第4章 连接 第5章 库函数 第6章 预处理器 第7章 可移植性缺陷 第8章 建议与答案

weixin_44588584的博客 520

《c陷阱与缺陷》学习总结

花了一天时间看完了传说中的c语言三杰中的最后一本书,毕竟这书才一百多页,讲的东西有些让我失望。看完之后还是把我觉得学到的东西记录一下 一、词法陷阱 1、编译器将程序分解成符号的方法是:从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么再读入下一个字符,重复判断,直到字符组成的字符串已不再可能组成一个有意义的符号。这个处理策略叫“贪心法”或“大嘴法” 2、整型常量的第一个

Jiang_XB的专栏 648

C陷阱与缺陷读书心得

《C语言陷阱与缺陷》中词法陷阱,语法陷阱,语义”缺陷“,连接,库函数,预处理器,可移植性缺陷。

chenemy的博客 1311

我读经典(2):《C陷阱与缺陷》学习笔记

最近,在工作之余,我抽时间阅读了一下经典书籍《C陷阱与缺陷》。本书以作者的实际C语言工作为背景,详细地介绍了用C语言进行编程工作过程中需要注意的一些细节。本书篇幅不多,但却将C语言程序员普遍遇到过的问题都包括进去了。该书很值得大家一读。 本书一共九章内容,章节结构如下图所示。 在阅读的过程中,我摘录了一些重要的语句,同时对某些观点作了相应的评论,请大家参阅。   第0章  导读 1

周兆熊的专栏 2844

《C陷阱和缺陷》读书总结随笔

《C陷阱和缺陷》读书总结随笔简介第一章 词法缺陷1.=不是==2.&和|不是&&和||3.贪心法第二章 句法缺陷1.运算符并不总是具有你所想象的优先级2.switch语句3.函数调用第三章 链接第四章 语义缺陷1.表达式求值顺序2.C 并不总是转换实参待续第五章 库函数1.返回整数的getchar函数第六章 预处理器1.宏不是函数第七章 可移植性缺陷第八章 这里是空闲空间 简介 进行对一些比较经典的书籍进行阅读,练习自己的内功,因为博主比较菜,所以近期会对一些书籍进行全面的总结,欢迎

努力学习的花椰菜的博客 515

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

《C陷阱与缺陷》    Andrew Koenig  著 本书主要帮助C程序员绕过编程过程中的陷阱和障碍。 第一章:词法“陷阱” 1.5 字符与字符串 用双引号引起的字符串,代表的却是一个指向无名数组起始字符的指针, 该数组被双引号之间的字符以及一个额外的二进制为零的字符'\0'初始化。 下面的这个语句: printf("Hello world\n"); 与 char hello[

rig622的专栏 1059

C陷阱与缺陷总结

1 符号 术语“符号”(token)指的是程序的一个基本组成单元,其作用相当于一个句子中的单词。编译器中负责将程序分解为一个一个符号的部分,一般称为“词法分析器”。  2 赋值符号 一般而言,赋值运算相对于比较运算出现得更频繁,因此字符数较少的符号=就被赋予了更常用的含义------ 赋值操作。  3 词法分析中的贪心法 表达式  a---b  应该怎样理解呢? 词法分析中的贪心法:每...

weixin_34313182的博客 199
上一篇: C++类成员指针
下一篇: 源码分析 | ClickHouse和他的朋友们(9)MySQL实时复制与实现
dbkernel
博客等级 码龄4年 60粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值