C语言设计哲学:
  一切工作程序员自己负责。
  语言中的所有特性都不需要隐式的运行时支持。
  程序员所做的都是对的。
  程序员应该知道自己在干什么,并保证自己的所作所为是正确的。

========

C专家编程

  • 第一章 C:穿越时空的迷雾
  • 第二章 这不是BUG,是语言特性(C语言本身存在的问题)
  • 第三章 分析C语言的声明
  • 第四章 令人正经的事实:数组和指针并不相同
  • 第五章 对连接的思考
  • 第六章 运动的诗章:运行时数据结构
  • 第七章 对内存的思考
  • 第八章 为什么程序员无法分清万圣节和圣诞节
  • 第九章 再论数组
  • 第十章 再论指针
  • 第十一章 你懂C,C++不在话下
  • 附 几个问题:
  • 心得体会和收获

第一章 C:穿越时空的迷雾

01 起源
1)Multics项目(小规模硬件系统运行巨大操作系统)—MIT,GE,Bell。- “小即是美”
2)UNIX,Ken Thompson;(BCPLB);C语言,Dennis Ritchie
小结:“小即是美”、“(编译器)效率几乎是一切”

02 特性
1)类型系统:帮助编译器设计者区分硬件支持的不同类型
2)数组下标:从0开始偏移量
3)基本数据类型与硬件相对应
4)auto:缺省的
5)表达式中的数组名可以看作是指针:简化区分机制
6)float自动转换为double
7)不允许函数嵌套
8)Register:简化了编译器,但程序员的任务加重
小结:为编译器设计者考虑的特性。

03 标准I/O库和预处理器
C编译器不曾实现的功能,就得由其他途径实现。
1)I/O最初由库函数提供,后来成为标准机制,由Make Lest编写
2)C预处理器:①字符串替换;②头文件包括;③通用代码模板扩展(注意宏空格)。
3)宏:最好只用来对命名常量,应该大写,以区分函数名;
小结:宏扩展中,空格会对结果造成很大影响,宏不是C语句,后不可加分号‘;’
04 K&R C
1)早期的C --> K&R C–> ANSI C --> C++;1978年The C Programming Language,该版本称为K&R C。
05 今日之ANSI C
1)防止C变种为多个松散的语言–>确立标准
2)应该使用ANSI C的标准,即美国国家标准化组织(1989年)–>ISO C(C90)
06 很棒,但符合标准吗
1)不可移植的代码:由编译器设计者决定采取何种行动
如,整型右移要不要扩展符号位,未确定的unspecified,参数求值的先后顺序
2)坏代码:未定义的undefined–在某些不正确的情况下的做法,标准未规定怎么做。
3)约束条件:不遵守就会成为未定义的
4)可移植的代码:严格遵守标准的成率–>①只使用已确定的特性;②不产生任何由编译器定义的undefined或unspecified输出;③不突破任何由编译器实现的限制。
5)遵循标准:可以依赖一些某种编译器特有的不可移植的特性。
07 编译限制
1)ANSI C对一个能够成功编译的程序的最小长度做了限制‘
2)每一个ANSI C编译器应该支持:
①函数定义形参上限至少为31个;
②函数调用实参上限至少为31个;
③一条源代码行里至少可以有509字符;
④表达式中至少可以支持32层嵌套的括号;
⑤long型整数不得低于32位。
08 ANSI C标准的结构
1)ANSI C标准出处和内容:总体介绍
2)K&R C和ANSI C区别:
①原型,是对声明的扩展;
②新的关键字–enum等;
③“安静的改变”–类型转换和类型提升;
④其他区别。
09 阅读ANSI C标准,寻找乐趣和裨益
1)参数传递类似于赋值;
2)赋值:两个操作数都指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须具有右边指针所指向类型的全部限定符;const char **指向有const限定符的char类型的指针的指针。
10 安静的改变
1)类型转换
2)类型提升

第二章 这不是BUG,是语言特性(C语言本身存在的问题)

01 这关语言特性何事,在Fortran里这就是Bug呀
1)语言细节决定语言是可靠的还是容易滋生错误;
02 多做之过:
1)fall through(case不加break,就会顺序执行),switch语句会带来麻烦,break与多重判断和循环嵌套时候,易混淆;
2)相邻的字符串常量会被自动合并,末尾逗号‘,’;
3)太多缺省可见性—缺省函数名全局可见,extern可加可不加,对应static;
03 误做之过:
1)符号重载—static、extern、void、*、&、<、( );
2)运算符优先级问题–有些专家建议在C语言中记牢两个优先级就够了:乘除先于加减,在涉及其他的操作符时一律加括号。
3)参数计算顺序—为了让编译器充分利用自身架构特点;
3)gets(char *s),不检查缓冲区的空间,而fgets(char *s, int n, FILE *stream)可以对读入的字符数设置一个上限n。fgets对缓冲大小进行限制的方式,更为安全。
04 少做之过:
1)空格—转义字符;
2)注释;
小结:即使可以保证你的编程语言100%可靠,你仍然可能成为算法中灾难的牺牲品。

第三章 分析C语言的声明

01 C语言声明的语法
1)“声明的形式和使用的形式相似”:如int p[3],使用时候p[i]
2)存储类型说明符(storage-class):extern,static, register,auto,typedef
3)类型限定符(type-qualifier):const,volatile
4)“在函数调用时,参数按照从右到左的次序压到堆栈里”这种说法过于简单,参数在传递时首先尽可能地存放到寄存器中(追求速度)
02 组合声明
1)结构体:struct 结构标签(可选) {
类型 标识符;
……
} 变量定义(可选);
结构中允许存在位段、无名字段以及字对齐所需的填充字段;
位段的类型必须是int,unsigned int 或 signed int(或加上限定词)。

struct pid_tag {unsigned int inactive : 1;unsigned int : 1; // 1个位的填充unsigned int refcount : 6;unsigned int : 0; //填充到下一个字边界short pid_id;struct pid_tag *link;}

结构体变量最好不要省略关键字struct,容易阅读。
2)联合:外表和结构体很相似,内存布局上不同。
①节省存储空间
②提取单独的字节字段(联合不需要额外的赋值和强制类型转换,同一个数据可解释为两个不一样的东西)

union bits32_tag {int whole;  /* 一个32位的值 */struct {char c0, c1, c2, c3;} byte;  /* 4个8位的字节 */
} value;

3)枚举:把一串名字和一串整型值联系在一起。
①缺省情况下,整型值从0开始,如果对列表某个标识符赋值了,那么紧挨后的标识符的值就比它大1,以此类推。
②枚举名字通常一直在调试器中可见。
03 优先级
规则:

A. 声明从它的名字开始读取,然后按照优先级顺序依次读取
B. 优先级从高到低依次是:
B1:声明中被括号扩住的部分
B2:后缀操作符()表示一个函数 []表示一个数组
B3:前缀操作符,*表示”指向…的指针”
C. 如果const,volatile后面紧跟类型说明符(如int),则他做用于类型说明符,否则作用于它左边紧邻的指针星号
如分析:char * const *(*next) ();

04 typedef 和define
1)typedef:并不是创建一个新的变量,而是宣称这个名字是指定类型的同义词;复杂函数声明
2)Typedef缺点:容易将多个声明器塞进一个声明中;
3)Typedef不能对定义的类型名进行扩展;可以保证连续定义的几个变量属于同一类型
05 typedef struct foo{…foo;}的含义
1)C语言中存在多种名字空间:
标签名(label name)
标签(tag)
成员名
其他
2)结构标签、结构类型、结构变量
对于typedef struct baz {int baz;} baz; 即相当于 typedef struct baz {int baz;} baz_type;
typedef声明引入了baz_type作为struct baz {int baz;}的简写形式
struct baz xxxxx; 使用的是结构标签
baz yyyyy; 使用的是结构类型
小结:应该始终在结构的定义中使用结构标签,可以使代码更为清晰。

第四章 令人正经的事实:数组和指针并不相同

01 数组并非指针
1)对编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址;
2)char *p = “abcdefgh”; …p[3] 先取符号表中p的地址;提取存储于此处的指针;把偏移量和指针相加,产生一个地址;访问这个地址,取得内容;
3)char a[] = “abcdefgh”; …a[3] 先取符号表中a的地址;把偏移量和这个地址相加,产生一个地址;访问这个地址,取得内容
4)注意两者区别:extern int *x;和extern int y[] 区别------声明x为int型指针,y为int型数组,长度未确定,存储在别处定义
02 声明和定义
1)声明相当于普通的声明:它所说明的并非本身,而是描述其他地方的创建的对象
2)定义相当于特殊的声明:它为对象分配内存
3)定义是声明的特殊情况,它分配内存空间,并可能提供一个初始值
03 左值
1)分类:可修改的左值(允许出现在复制语句左边)和不可修改的左值
2)数组名是左值,但不能作为赋值的对象(左值即为可取地址的值),编译器为每隔对象(变量)分配一个地址(左值)
3)左值在编译时候才知道,右值是存储地址内容的,在运行时才可知
4)举例,取得extern chara[10]的值和extern char *p的值,过程不一样–偏移,取地址的地址
04示例说明图

05 其他(与第九章结合)
1)在C语言中,所有非数组形式的数据均以传值形式调用
2)多维数组初始化时,可省略最左边下标的长度(也只能是最左边),如int rhubarb[][3] = { {0, 0, 0}, {1, 1, 1},};
3)指针数组就是Iliffe向量, char *pea[4]
4)指针数组必须用指向为字符串而分配的内存的指针进行初始化
5)“数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写成为“数组的指针”,而不是“指针的指针”
6)向函数传递一个一位数组:增加一个额外的参数或者赋予数组最后一个元素一个特殊的值
7)向函数传递一个普通的多维数组:必须提供除了最左边一维以外多有维的长度。即多维数组最主要的一维长度不必显式书写

第五章 对连接的思考

01 编译器的组成:
预处理器(preprocessor)、语法和语义检查器(syntactic and semantic checker)、代码生成器(code generator)、汇编程序(assembler)、优化器(optimizer)、链接器(linker)。
02 使用和查看
1)-#选项查看编译过程的各个独立阶段
2)通过给编译器驱动器一个特殊的-W选项(表示传递这个选项到那个阶段)向各个阶段传递选项信息,如cc -W1, -m mainc > main.linker.map,其中-m选项是传递给链接-载入器的,要求其产生连接器映像
03 动态链接
1)动态链接:执行文件只是包含了文件名,让载入器在运行时能够寻找程序所在的函数库。
2)动态链接目的:动态链接的主要目的就是把程序与它们使用的特定函数库版本中分离出来。这种介于应用程序和函数库二进制可执行文件所提供的服务之间的接口,称之为二进制接口(Application Binary Interface, ABI)
3)函数库:libc(C运行时库), libsys(其他系统函数), libX(X Windowing), libnsl(网络服务)
4)创建:动态链接库,可由ld创建,后缀名约定以.so结尾,表示shared object,简单的可以通过cc的-G选项来创建
5)优点:体积小、共享单独的拷贝、函数库的版本升级更为容易
04 静态库
1)概念:函数的一份拷贝是可执行文件的物理组成部分
2)创建:静态库称作为archive,通过ar来创建和更新,后缀名约定以.a结尾
生成示例
cc -o libfruit.so -G tomoto.c
使用示例
cc test.c -L/home/swf -R/home/swf -lfruit, -L, -R 分别告诉链接器在链接和运行时从哪个目录找需要链接的函数库
05 函数库链接的秘密
1)动态库文件的扩展名是“.so”,而静态库文件名是“.a”
2)传给C编译器的命令行参数里并没有提到函数的完整路径名。他甚至没有提到在函数库目录中该文件的完整名字;
-lthread选项告诉编译链接到libthread.so,即libname.so对应于-lname
3)编译器期望在确定的目录找到库;
链接时一般使用-Lpathname,-Rpathname,默认读取系统变量LD_LIBRARY_PATH和LD_RUN_PATH等
4)观察头文件,确认所使用的函数库;
①头文件的名字通常并不与它所对应的函数库名相似。
②函数库包含许多函数的定义,但这些函数的原型声明却散布于多个头文件中

5)与提取动态库中的符号相比,静态库中的符号提取方法限制更严。

注意:始终将-1函数库选项放在编译命令行的最右边,很多人习惯<命令><选项><文件>,但链接器采用这个容易引起混淆。
nm工具可列出函数库中包含的函数, nm libc.so | grep xdr_reference
06 Interpositioning
就是就是通过编写与库函数同名的函数来取代该库函数的行为(与C++多态类似)。

第六章 运动的诗章:运行时数据结构

01 学习运行时系统目的:①优化代码,②理解其他,③分析问题
02 a.out:
1)assembler output汇编程序输出缩写,实际为链接器输出
2)UNIX中可执行文件是以一种特殊的方式加上标签的,这样系统就能够确认它的属性。
①为重要的数字定义标签,用独特的数字唯一地标识数据,是一种普遍采用的编程技。
②标签所定义的数字通常被称为“神奇”数字
③ELF (Executable and Linking Format)可执行文件和链接格式。UNIX中可man a.out 查看有关UNIX系统所使用的格式的信息。
03 段segments
1)概念:
①unix中,段表示一个二进制文件相关的内容块
②Intel x86的内存模型中,段表示一个设计的结果,其中地址空间并非一个整体,而是分成了一些64K大小的区域,称之为段。
2)size a.out可查看可执行文件中的三个段大小(数据段data,文本段text,bss段)
3)BSS段这个名字是“Block Started by Symble” 由符号开始的块的缩写,其不保存在目标文件中(除了记录BSS段在运行时所需要的大小)。
4)查看可执行文件的内容,nm和dump工具也可以
5)各个段保存内容
① 数据段保存在目标文件中,存储初始化的全局和静态变量以及它们的值
② BSS段不保存在目标文件中(除了记录BSS段在运行时所需要的大小)
③ 文本段是最容易受优化措施影响的段,存储可执行文件的指令
④ a.out文件的大小受调试状态下编译的影响,但段不受影响
局部变量不进a.out,他们在运行时创建。
6)操作系统里段就是一片连续的虚拟地址
04 操作系统在a.out里干了什么
1)文本段包含程序的指令,链接器把指令直接从文件拷贝到内存,以后再也不管它
2)数据段保存初始化的全局变量和静态变量以及它们的值,一般情况下,任何进程中数据段是最大的段
3)堆栈heap,保存局部变量、临时数据、传递到函数中的参数等。
4)可执行文件在内存中布局:

05 运行时的a.out(可执行文件)
1)运行时数据结构:堆栈、活动记录、数据、堆
2)堆栈段有三个主要用途:①为函数内部声明的局部变量提供存储空间;②进行函数调用时,堆栈存储与此相关的一些维护信息;③堆栈也可以被用作暂时存储区;
06 函数调用:
1)过程活动记录:可能不一定位于堆栈中,可能在寄存器中—提高速度;
2)头文件/usr/include/sys/frame.h描述了过程活动记录在unix系统中的样子
3)悬挂指针dangling pointer
07 关键字auto和static
1)static 可保证数据存在数据段中而不是堆栈中
2)auto 对于程序员来说,基本用不上,通常由编译器设计者使用,用于标记符号表的条目——它表示“在进入该块之后,自动分配存储”(与编译时静态分配或在堆上动态分配不同)
08 控制线程
1)setjmp()和longjmp()是通过操作过程活动记录来完成的,其在C++中变异为更普通的异常处理机制catch和throw
2)goto语言不能跳出C语言当前的函数
3)longjmp()可以跳回到曾经到过的地方
4)setjmp()/longjmp()最大的用途是错误恢复
09 C语言工具
检查源码的工具、检查可执行文件的工具、帮助调试工具、性能优化工具
10 优化代码技巧
消除循环;函数代码就地扩展;公共子表达式消除、改进寄存器分配、省略运行时对数组边界的检查、循环不变量代码移动(loop-invariant code motion)、操作符长度削减(指针操作符转变为乘法操作,把乘法操作转变为位移操作或假发操作)。
11 其他
1)8086中有代码寄存器CS,数据寄存器DS,堆栈寄存器SS
2)磁盘制造商都是采用十进制数而不是二进制数来表示磁盘的容量
3)billion和trillion在美语和英语中的意义不一样,美语中分别是十亿和一万亿,英语中是一万亿和100亿亿
4)/usr/ucb/pagesize可查看系统中页面大小,页就是操作系统在磁盘和内存之间移来移去或进行保护的单位。
5)用于管理内存的调用是:
①malloc 和 free —— 从堆中获取内存以及把内存返回给堆
②brk 和 sbrk —— 调用数据段的大小至一个绝对值

第七章 对内存的思考

01 Intel 80x86系列
1)4004开创事业,8008带来财富,8086跻身豪门—兼容性
2)内存技术:
①虚拟模式—段寄存器不与偏移地址相加,而是为一个存放实际段地址的表提供索引,也称位保护模式
②Intel 8086寻址模式
02 Intel 80x86内存模型以及工作原理
03 虚拟内存
1)提出:物理内存限制程序
2)原理:把暂时不用的数据搬到硬盘上,节约物理内存多层存储
3)内存媒介:磁带、磁盘、内存、cache存储器、CPU存储器(速度加快,价格高)
4)管理:CPU—MMU内存管理单元—虚拟地址—物理内存—物理磁盘。

04 Cache存储器
1)多层存储器的扩展:容量小、速度快、价格高,位于cpu和内存之间,极快的缓冲区;

05 数据段和堆
1)堆:用来完成数据段对象自动增长的任务,类似于堆栈自动增长
2)堆向下增长,由程序员动态分配malloc,为了圆整一般取2的乘方,堆的末端由一个break指针标识
3)堆的位置

06 内存泄漏–堆
1)问题:①内存损坏—释放或改写正在使用的内存;②内存泄漏—未释放不再使用的内存;
2)检测内存泄漏:swap查看可用交换空间-确定可疑进程
07 总线错误
1)总线错误:未对齐的读写问题-----字节对齐问题,未对齐内存访问,地址总线阻塞
2)段错误:内存管理错误,指针非法值
3)微妙:导致指针具有非法值通常由于变成错误引起,段错误像是间接症状;更微妙是未初始化指针恰好未对齐,会报总线错误而不是段错误。Cpu先看到地址,再发送给MMU
4)常见错误:①坏指针-未赋值就引用,②改写—越界读写,③-指针释放-同一块释放两次

第八章 为什么程序员无法分清万圣节和圣诞节

01 “寻常算术转换”
1)小于int或double的的表达式:如printf(“%d”, sizeof ‘A’);----4
2)类型提升:整形提升,除了float会到double
3)参数也会类型提升:也是为何%d能适用几个不同类型short, char, int。
4)注意点:隐式类型转换期初为了简化编译器
02 原型之痛
1)主要风格:K&R C和 ANSI C
2)问题:声明和定义不相符,容易混淆结果—实参和形参与期望不相符。
03 不按回车符就得到一个字符
1)Unix下一锅端,利于整行的输入
2)I/O函数可供调用回显输入
04 C语言实现状态机
05 强制类型转换
1)目的:消除歧义,类型转换,如(float) 3和(float) 3.0
2)复杂类型转换:合理去除标识符和限定符

第九章 再论数组

01 数组和指针不相同的场景:
声明时候:有区别
1)数组的声明:外部数组声明,数组定义,函数参数声明。
2)注意相同情况:所有作为函数参数的数组名总是可以通过编译器转换为指针。
3)不同:其他情况都必须分开,决不能“一个文件定义为数组,在另一文件声明为指针”。
使用(语句或表达式引用中)时候:数组总是可以写成指针的形式,两者可以互换。
什么时候数组和指针相同:三个规则
1)“表达式中的数组名”就是指针;
2)C语言把数组下表作为指针的偏移量;
3)“作为函数参数的数组名”等同于指针
02 为什么C语言把数组当作形参
1)出于效率的考虑
2)数组/指针实参的一般用法

3)数组名不可以被赋值,指针可以-指针变量,数组名一旦声明,不能改变
03 数组和指针可交换性的总结
1)a[i]被编译器“改写”成*(a+i)
2)指针始终是指针,可以用下标形式访问,但绝不可以写成数组;
3)作为函数参数时候,数组声明可以看成指针
4)函数参数,可以定义为指针或数组
5)其他情况,声明和定义必须分开。若定义了数组,则在其他文件里对它声明也要为数组。
04 多维数组
1)存储:连续存储
2)分解:从最左边开始,逐层分解
3)数组初始化:长度和值的初始化
尤其注意二维字符串数组初始化的特殊性,与二维其他数组(如int)型数组不同。

第十章 再论指针

01 多维数组内存布局
1)说明:多维数组在编程中并不多见
2)布局:并非是想表格一样在各行中排列,而是线性的排布,如图:

02 指针数组是Iliffe向量
1)通过声明一个一维指针数组,其中每个指针指向一个字符串来取得类似二维数组的效果
2)小标方括号优先级高于星号:注意 char *p[23]和(char *)p[23]不同
3)squash[5][6]的四种形式:
int squash[23][12]; //
int *squash[23]; //指针数组
int **squash; //二重指针
int (squash)[12]; //数组指针
4)数组的数组和多维数组:
前者char a[5][6]表示a是一个包含4个元素的数组,每个元素是一个char型的数组。
后者char p[4]表示p是一个字符串指针数组,包含4个元素的数组,每个元素为一个指向char的指针。
03 锯齿状数组–字符串指针数组
1)优点:各行长度可以不一样;可以向函数传递一个字符串数组;
2)数组和指针:编译器解析时候会将数组的数组改写为“数组的指针”;

实际情况:
(
(p + i) + j)
04 使用指针向函数传递一个多维数组:
如将二维数组改写成一个指向向量的指针数组
05 使用指针从函数返回一个数组:
不能返回指向局部变量的指针
06 NULL使得printf崩溃:
因为C规定%s说明符的参数必须是指向字符串的指针
07 使用指针创建和使用数组:
注意const常量不能用在类似于case后以及数组下标a[]

第十一章 你懂C,C++不在话下

01 初识OOP
1)OOP(object-oriented- paradigm):面向对象编程模型
2)特点:继承–类的派生、动态绑定–虚拟函数
3)术语:
抽象(abstraction):去除对象不重要的细节过程,只保留对象关键点。设计活动
类(class):用户定义的类型,类似于int,struct
对象(object):某个类的特定变量,也称类的实例
封装(encapsulation):把类型、数据、函数组合在一起,组成类。C的头文件
继承(inheritance):允许类从一个更简单的基类中接收数据结构和函数
02 抽象
1)抽象–>面向对象设计–>面向对象编程
2)抽象:只记录能表现事物关键特征数据;本质特征;“黑盒子”;分工‘代码重用和共享;
02 封装
1)自上而下:把用户定义的类型中各种数据和方法组合在一起
2)自下而上:把各种数据和方法组合在一起实现一种用户定义类型
3)类:把代码和相关数据封装(捆绑)在一起
03 类 和 访问控制
1)类:用户定义类型+所有对该类型进行的操作
2)类实现形式:一个包含多个数据的结构+对这些数据进行操作的函数指针
3)编译器实行强类型:即该类型的数据只能进行该操作
4)访问控制关键字:public–外部可见,protected–该类的函数以及该类派生类的函数,private–只能被该类成员函数使用-外部可见但不可用,friend–不属于该类,但可以访问该类,virtual–虚拟函数
04 声明
1)类声明:就是正常的C声明,包括函数、类型、数据
2)注释:始于//,止于行尾
3)成员函数在外部实现:前缀::
4)成员函数的调用:附上类名,如 melon.slice()
5)构造函数和折构函数:初始化和垃圾清理
05 继承
1)单继承:唯一基类
2)区别“类嵌套”和“类继承”:继承是类的变型
3)多重继承:
06 重载
1)概念:就是重复使用一个现存的名字
2)对象:函数名、操作符
3)编译时进行解析
07 C++如何进行操作符重载
1)先定义操作原型----->为重载的操作符提供一个函数体
08 C++的I/O
1)C++有自己的库,提供I/O接口
2)操作符:<< >>
09 多态
1)概念:一个函数或操作符只有一个名字,但可以用于几个不同的派生类型的能力;
2)运行时决定用哪个成员函数,“后期绑定”;
3)关键字:virtual
4)与interposing有几分类似
5)其他:模板template,异常exception,内联inline,new和delete,传引用调用call-by-reference

附 几个问题:

01 几个增值语句的区别:
a = a + 1;
++a;
a++;
a += 1;
mango[i++] += y;-------> mango[i] = mango[i] +y; i++,不是mango[i++] = mango[i++] +y;
02 库函数调用和系统调用
库函数调用是语言或应用程序的一部分;系统调用是操作系统的一部分。
03文件描述符和文件指针
文件描述符:一个小整数,用于索引开放文件的每个进程表,开放文件的每个进程表的偏移量,用于UNIX标识文件
FILE指针:保存一个FILE结构的地址

心得体会和收获

1)开卷有益:坚持读完该书,对现有基础知识的认知得到增强,尤其是对指针和数组、内存有了更深刻的认识和理解;
2)个人对本书的评价:书中有些问题介绍的不很详细,需要查阅资料加以理解;另外有些翻译读起来很奇怪,理解上不是特别顺畅;但总体还是非常棒的一本C语言书
3)后面读书计划:希望自己能通过这次的锻炼坚持过程,能养成坚持抽时间读书的习惯,多读几本好书。

C专家编程-读书笔记(书本顺序)相关推荐

  1. C专家编程 读书笔记

    在ANSI C中,如果要声明空参数表,则必须使用关键字void进行显式声明: CPU,16位地址总线,能够访问2^16也就是64KB的内存:20位地址总线,可以访问2^20也就是1MB的内存:32位地 ...

  2. C专家编程读书笔记一:C语言晦涩难懂的声明

    理解C语言声明的优先级规则: 声明从它的名字开始读取,然后按照优先级顺序依次读取 优先级从高到低依次是: B1     声明中被括号括起来的那部分 B2     后缀操作符:括号()表示是一个函数,二 ...

  3. C专家编程--读书笔记九 再论数组

    第九章 一.知识点 1.所有作为函数参数的数组名总是可以通过编译器转换成指针. 然而,数组和指针在编译器处理时是不同的,在运行时的表示形式也是不一样的,并可能产生不同的代码.对编译器而言,一个数组就是 ...

  4. C专家编程--读书笔记十 再论指针

    第十章 一.知识点 1.C标准规定%s说明符的参数必须是一个指向字符数组的指针.所以如: char *p = NULL; printf("%s", p); 这是不正确的.NULL是 ...

  5. C专家编程--读书笔记六 运行时数据结构

    第六章 一.知识点 1.代码和数据的区别也可以认为是编译时和运行时的分界线.编译器的绝大部分工作都跟翻译代码有关:必要的数据存储管理的绝大部分都在运行时进行.(P121) 2."a.out& ...

  6. c专家编程 读书笔记

    c诡异离奇,缺陷重重,却获得了巨大的成功 编译器设计者的金科玉律:效率=一切 c预处理器:1.字符串替换 2.头文件包含 3.通用代码模板的扩展 预处理一定要使用强制类型转换!!!明确数据类型 每一个 ...

  7. 《程序员修炼之道–从小工到专家》读书笔记

    <程序员修炼之道–从小工到专家>的读书笔记 <程序员修炼之道–从小工到专家>[美]Andrew Hunt / David Thomas 著 马维达 译 看这本书主要使用了检视阅 ...

  8. UNIX网络编程--读书笔记

    会集中这段时间写UNIX网络编程这本书的读书笔记,准备读三本,这一系类的文章会不断更新,一直会持续一个月多,每篇的前半部分是书中讲述的内容,每篇文章的后半部分是自己的心得体会,文章中的红色内容是很重要 ...

  9. mozart-oz中有限域编程读书笔记

    mozart-oz自带文档: <Finite Domain Constraint Programming in Oz. A Tutorial.>读书笔记 http://www.mozart ...

最新文章

  1. bootstrap之双日历时间段选择控件—daterangepicker(汉化版)
  2. python中文件读写位置的作用-Python中文件的读写、写读和追加写读三种模式的特点...
  3. 人脸识别有什么漏洞,活体检测又是怎么防伪?
  4. php html 伪静态,php 伪静态(url重写)的写法
  5. 【 Grey Hack 】大数四则运算
  6. java调用dubbo服务器_dubbo源码分析-服务端注册流程-笔记
  7. 交通流元胞自动机模拟仿真 matlab源码_元胞自动机中的时间反演
  8. js图片加载效果(延迟加载+瀑布流加载)
  9. 【go】metrics基本使用
  10. 关于 Linux 的配置文件 /etc/profile 路径出错后相关的命令失效解决方式(如:ls,vi不能用)...
  11. Java 操作 JSON
  12. 透彻理解cmake(含PRIVATE,PUBLIC,INTERFACE的详细解释)
  13. FLV转MPG和转成其它格式的转码方法
  14. java文件复制后是乱码_复制Java源文件到MyEclipse后乱码问题怎么解决?
  15. android 雷达搜索动画,Android特效专辑(九)——仿微信雷达搜索好友特效,逻辑清晰实现简单...
  16. 【语音信号处理】3语音信号可视化——prosody
  17. Axure RP 8的介绍
  18. 给SAP初学者的建议!
  19. Typora导入CSDN
  20. 机器人香囊_中山街道仪凤街社区开展“能手包粽子 巧手绣香包”欢度端午节活动...

热门文章

  1. 虚拟机文件格式详解 .VMX .VMSD .VMDK .NVRAM .VMX.LCK
  2. Qtum量子链关键技术解读
  3. 5G,一场商业噱头 or 一次技术革命?
  4. 计算机不被淘汰的知识,李开复:未来50%的职业将被淘汰,女儿的一个问题让我深思...
  5. jay《七里香》-工作之余大家也放松放松
  6. Python有道翻译2.1版本爬虫实现
  7. vue js IOS H5focus无法自动弹出键盘的解决方法
  8. IDEA配置Profiles
  9. HPE公司收购Cloud Cruiser,旨在对IT资源使用情况进行量化
  10. 俄罗斯商标注册的相关规定