1.关键字类
1.register
作用:请求编译器尽可能将变量存在CPU内部的寄存器(寄存器数量是有限的,因此是尽可能)
寄存器:小的存储空间,存取速度比内存快很多,离CPU近
注意事项:
1.register变量要是CPU寄存器接受的类型,长度小于等于整型长度
2.register变量不存在内存中,不能通过取址运算符&获取变量地址
2.static
两个作用:修饰变量和修饰函数
1.修饰变量:使得变量都存在内存的静态区
修饰局部变量:函数运行结束,静态变量的值不会被销毁,下次还能继续使用
修饰全局变量:作用域限定在本文件中(从定义开始到文件结尾处),其他文件用extern也无法使用
2.修饰函数
主要是限定函数作用域,只能在本文件中使用该函数(又称为内部函数)
3.sizeof
注意:是关键字而不是函数,也可以说是运算符
1.sizeof计算变量大小空间时,括号可以省略,计算数据类型时,括号不能省略
2.sizeof(一个指针),在32位系统中,固定为4个字节,64位系统中,固定为8个字节
例子:
int b[100]属于全局数组,数组作为函数参数时退化成指针(很重要)
因此上述结果为4(32位系统)
4.break和continue
break:终止本层循环
continue:终止本轮循环
5.void
- 注意void*(void指针)不能进行算法操作,因为没有分配内存
- void 不能代表一个真实的变量
6.const
可以节省空间,提高效率
编译器通常不为普通const只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高
常问:const 和 define 的区别
7.volatile
易变、不稳定,常用于防止编译器优化
8. extern
声明外部函数或者变量(其他源文件)
extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中
9.struct
多种数据整合成为一个整体
1) 空结构体内存:1Byte
2) struct 和 class 的区别:默认的成员属性不一样
struct :默认public属性
class :默认private属性
10.union
union的空间大小为最大成员的大小,所有成员共用一个空间,同一时间只能存储一个成员,且所有成员的起始地址相同(根据此特性来写函数判断大小端)
判断大小端函数:
大端模式:符合人们常用的阅读习惯,高字节存在低地址上
小端模式:高字节存在高地址上
常问:union 和 struct 的区别(存储方式、初始化)
操作运算符:
算数运算符高于位移运算符
逗号运算符优先级最低
2.函数类
1.if else 组合
1.bool变量与零值比较
bool flag
推荐写法: if(flag) 或者 if(!flag)
注:FALSE值在编译器中被定义为0,但是TRUE的值不一定为1,不同的编译器中不同,可能为1,也可能为-1
2. float 变量与零值比较
float x = 0.0;
推荐写法:if(x >= -EPSINON) && (x <= EPSINON);
tips: 由于float是有一定精度限制的,通过EPSINON来设置精度,如果这个数落在 [0.0 - EPSINON, 0 + EPSINON] 中,则认为和0相等
3. 指针变量和零值比较
int *p = NULL;//注意,定义指针要记得初始化,不一定非要是NULL
推荐写法:if(NULL == p) 或者 if(NULL != p)
2. switch case 组合
1. case 后面的值要求
只能是整型或字符型常量或者常量表达式(字符型本质上也是整型)
2. case 中忘记加break
当匹配到某个case时,但缺少break,则程序会一直运行之后的case知道遇到break为止
3. 指针和数组
3.1 指针
1. 基础
- 指针是什么:存储地址的变量,指针变量 p 中存储的任何数据都被当作地址来处理
- sizeof(p):在32位系统中,固定为4byte(64位则为 8 byte),与 p 的类型无关
2. int *p = NULL 和 *p = NULL 的区别
int *p = NULL:初始化指针变量p,指针 p 的值为 0x00000000
*p = NULL:赋值,*p 的值为0,p指向的内存可能非法
注:NULL 和 NUL 的区别,NULL一般被宏定义为0,而NUL是ASCII码表的第一个字符
3.2 数组
1. 基础:
- 定义:一组相同数据类型的元素,内存连续排布
- int a[5],数组名 a 代表数组首元素的首地址
sizeof(a) = 20
sizeof(a[0]) = 4
sizeof(a[5]) = 4 编译器不能检测数组越界,只是根据元素类型来确定值
- &a[0] 和 &a 的区别:值相同,但意义不同
&a[0]:数组首元素的首地址
&a:数组的首地址
- 数组名a 作为左值和右值
C语言引入一个术语-----“可修改的左值”。意思就是,出现在赋值符左边的符号所代 表的地址上的内容一定是可以被修改的。换句话说,就是我们只能给非只读变量赋值
1)a作为左值 !!!(不存在)
编译器会认为数组名作为左值代表 的意思是a的首元素的首地址,但是这个地址开始的一块内存是一个总体,我们只能访问数组的某个元素而无法把数组当一个总体进行访问。所以我们可以把a[i]当左值,而无法把 a 当左值
2)a 作为右值
此时代表的是数组首元素的首地址,意义和&a[0]一样
3.3 指针和数组
二者毫无关系
1)以指针形式和下标形式访问指针
读取字符e
- 指针形式:*(p+4)
- 下标:p[4]
2)以指针形式和下标形式访问数组
读取字符5
- 指针形式:*(a+4)
- 下标:a[4]
3)例子
int a[5] = {1, 2, 3, 4, 5}
- a:a[0]的地址
- &a:数组的首地址,值和a相同
- a + 1:addr(a[0]) + sizeof(int)
- &a + 1:addr(a[0]) + 5*sizeof(int)
指针和数组的对比
指针 | 数组 |
指针变量p保存数据的地址,至于p的本身的地址不关心 | 保存同类型的数据,数组名a表示数组首元素的首地址 |
间接访问数据 | 直接访问数据 |
通常用于动态数据结构 | 用于存储固定数据且数据类型相同的元素 |
相关函数为malloc和free | 隐式分配和删除 |
3.4 指针数组和数组指针
- 指针数组:一个数组,元素都为指针
int *p1[10]:优先构成数组定义([ ] 优先级高于 *)
- 数组指针:指向数组的指针
int (*p2)[10]:优先构成指针定义(()优先级最高)
数组指针原型:int (*)[10] p,其中指针类型是int (*)[10],p为指针变量