1.变量
2.操作符
3.指针
4.数据类型
5.函数
6.宏
7.编译运行原理
8.杂项
9.附录
---------------------------------------------------------------------------------------
16位机整型 | 32位机整型 | 浮点型 | 字符型 | 结构体 | 共用体 | 指针 | 空类型 |
short 2 | short 2 | float 4 | char 1 | 结构体大小等于最宽数据类型大小的整数倍 | 共用体大小等于最大成员4字节对齐后的长度 | 指针大小等于机器字长 | 0 |
int 2 | int 4 | doule 8 | |||||
long 4 | long 8 |
枚举变量的大小,实质是常数所占内存空间的大小(常数为int类型,32位机器和64位机器中int型都是4个字节),枚举类型所占内存大小也是这样。
结构体大小
(1)数据成员对齐规则:(原则1)
结构体struct的数据成员,第一个数据成员放在offset为0的地方,之后每个数据成员的起始位置要从该成员大小的整数倍开始。(比如int在32位机上要从4的整数倍开始存储) 。
(2)结构体作为成员 :(原则2)
如果一个结构体里面同时包含结构体成员,则结构体成员要从其内部最大元素的大小的整数倍地址开始存储(比如struct a里面有struct b, struct b里面有char ,int , double元素,那么b应该从8(也就是double类型大小)的整数倍开始存储) 。
(3)结构体的大小 :(原则3)
即sizeof的结果。在按之前的对齐原则计算出大小的基础上,必须还得是其内部最大成员的整数倍,不足的要补齐(如struct 里面最大的为double,现在计算得到的已经是11了,则总大小为16)。
---------------------------------------------------------------------------------------
优先级 | 运算符 | 含义 | 操作数数目 | 结合方向感 |
---|---|---|---|---|
1 | () [] -> . | 括号(函数等),数组,两种结构成员访问 | 双目 | 左-右 |
2 | ! ~ ++ -- + - |* & (类型) sizeof | 否定,按位取反,自增,自减,正负号,间接,取址,类型转换,求大小 | 单目 | 右-左 |
3 | * / % | 乘,除,取模 | 双目 | 左-右 |
4 | + - | 加,减 | 双目 | 左-右 |
5 | << >> | 左移,右移 | 双目 | 左-右 |
6 | < <= >= > | 小于,小于等于,大于等于,大于 | 双目 | 左-右 |
7 | == != | 等于,不等于 | 双目 | 左-右 |
8 | & | 按位与 | 双目 | 左-右 |
9 | ^ | 按位异或 | 双目 | 左-右 |
10 | | | 按位或 | 双目 | 左-右 |
11 | && | 逻辑与 | 双目 | 左-右 |
12 | || | 逻辑或 | 双目 | 左-右 |
13 | ? : | 条件 | 三目 | 右-左 |
14 | = += -= *= /= &= ^= |= <<= >>= | 各种赋值 | 双目 | 右-左 |
15 | , | 逗号(顺序) | 双目 | 左-右 |
逗号运算符:表达式1,表达式2 先算表达式1,再算表达2,整个式子是表达式2的值。
为了可以在参数里面写语句,C语言很多东西都是为了把多个语句塞进一个表达式里面而弄出来的
1
2
3
4
5 |
|
宏定义的时候可以用到,作为一个表达式使用
sizeof当参数分别如下时,sizeof返回的值表示的含义如下:
数组——编译时分配的数组空间大小;
指针——存储该指针所用的空间大小(为4);
类型——该类型所占的空间大小;
对象——对象的实际占用空间大小;
函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。
---------------------------------------------------------------------------------------
指令集里面有一种间接寻址的方式,抽象出来就是指针。
变量为了表示数据而生, 指针为了传递数据为生。
注意: 1. 申请内存后要检查,释放内存前要检查。
2.指针使用要强烈注意判断是否为NULL,初始化,越界问题
- int p; //这是一个普通的整型变量
- int *p; //首先从P 处开始,先与*结合,所以说明P 是一个指针,然后再与int 结合,说明指针所指向的内容的类型为int 型.所以P是一个返回整型数据的指针
- int p[3]; //首先从P 处开始,先与[]结合,说明P 是一个数组,然后与int 结合,说明数组里的元素是整型的,所以P 是一个由整型数据组成的数组
- int *p[3]; //首先从P 处开始,先与[]结合,因为其优先级比*高,所以P 是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与int 结合,说明指针所指向的内容的类型是整型的,所以P 是一个由返回整型数据的指针所组成的数组
- int (*p)[3]; //首先从P 处开始,先与*结合,说明P 是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P 是一个指向由整型数据组成的数组的指针
- int **p; //首先从P 开始,先与*结合,说是P 是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与int 结合,说明该指针所指向的元素是整型数据.由于二级指针以及更高级的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针.
- int p(int); //从P 处起,先与()结合,说明P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数,然后再与外面的int 结合,说明函数的返回值是一个整型数据
- Int (*p)(int); //从P 处开始,先与指针结合,说明P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P 是一个指向有一个整型参数且返回类型为整型的函数的指针
- int *(*p(int))[3]; //可以先跳过,不看这个类型,过于复杂从P 开始,先与()结合,说明P 是一个函数,然后进入()里面,与int 结合,说明函数有一个整型变量参数,然后再与外面的*结合,说明函数返回的是一个指针,,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,然后再与int 结合,说明指针指向的内容是整型数据.所以P 是一个参数为一个整数据且返回一个指向由整型指针变量组成的数组的指针变量的函数.
- #define MAX(x,y) ((x)>(y) ? (x) :(y))
- #define MK_ID(n) i##n
- int MK_ID(1), MK_ID(2), MK_ID(3);
- //预处理后声明变为:
- int i1, i2, i3;
- #define GENERIC_MAX (type) \
- type type##_max(type x, type y) \
- { \
- return x > y ? x :y; \
- }
- GENERIC_MAX(float)
宏定义中的do-while循环 do循环(0)必须始终随跟着一个分号;作为一句话。
__LINE__ 被编译的文件的行数
__FILE__ 被编译的文件的名字
__DATE__ 编译的日期(格式"Mmm dd yyyy")
__TIME__ 编译的时间(格式"hh:mm:ss")
__STDC__ 如果编译器接受标准C,那么值为1
8.杂项
值语义
sizeof