文章目录
1.指针
1.1什么是指针:
1、指针是一种数据类型,使用它可以定义指针变量,简称指针。
2、指针变量中存储的是整数,这种整数表示的是内存地址。
3、可以根据指针变量中存储的内存地址去访问对应的内存。
*指针变量; // 根据指针变量中存储的内存地址去访问对应的内存块,具体访问多少个字节,由指针变量的类型决定,如果之前赋值的是非法的内存地址,此时会出现段错误。
int num;
int* p = #
*p <=> num; // *p 等价于 num
1.2指针变量的定义:
类型* 指针变量名
1、由于指针变量的使用方法与普通变量不同,所以要从名字加以区别,一般以p结尾。
2、指针变量的类型决定使用访问内存时的字节数,指针变量中存储的是一个内存块的第一个字节的地址。
int* p; // 用p访问内存时一次访问4字节
short* p; // 用p访问内存时一次访问2字节
double* p; // 用p访问内存时一次访问8字节
3、指针变量的默认值与普通变量一样是随机的(野指针),为了安全一般定义指针变量时要初始化,如果不知道赋什么值可以初始化为NULL(空指针)。
4、指针变量不能连续定义
int* p1,p2; // p1是指针变量,p2是int类型变量
int *p1,*p2; // p1、p2都是指针变量
1.3指针变量的赋值
指针变量 = malloc(size); // 向malloc申请一块size字节的堆内存,malloc会返回这个内存块的首地址
指针变量 = &普通变量; // 计算出普通变量的内存块首地址赋值给指针变量
把一个合法内存地址赋值给指针变量,该步骤也叫引用或绑定,如果赋值是非法内存地址,此时也不会出错。
指针变量 = 指针变量; // 必须类型相同
1.4什么情况下使用指针:
1、函数之间共享变量。
由于全局变量在使用期间无法释放,所以会造成内存浪费,并且会与其它全局标识符有命名冲突,因此全局变量尽量少最好不用,而使用指针就可以让函数之间共享变量。
函数之间共享变量可以让调用者返回多个数据,例如:
int scanf(const char *format, ...);
// 调用scanf时需要返回多个数据
1、终端输入的数据
2、成功或失败的状态
2、提高函数的传参数效率
由于C语言函数传参是单向值传递,就是一个变量给另一个变量赋值,也就是把一个变量内存中的内容,拷贝给另一个变量。
当变量的字节数较多时,这种单向值传递比较耗时,而传递变量的地址,只需要拷贝4个字节的数据,这样就可以大大节约函数的传时间。
注意:使用指针提高函数的传参效率时,变量就有了被破坏的风险,可以使用 const 类型* 指针 进行保护变量。
3、建立联系
由于堆内存无法取名字(无法用变量名与堆内存建立联系),所以使用堆内存必须与指针变量配合。
1.5 使用指针需要注意的问题
空指针:
指针变量的值是NULL,这种指针变量叫空指针,只要对空指针解引用就会产生段错误,操作系统规则NULL地址不能访问。
返回值是指针类型的函数,如果返回NULL则表示该函数指针出错,所以NULL也是函数出错的标志。
如何避免空指针产生的段错误:
对来历不明的指针解引用前要进行判断。
1、函数的参数
2、函数的返回值
2.野指针
2.1 野指针的定义
指针变量的的值是不确定的、随机的,这种指针变量叫野指针,对这种指针变量解引用可能会产生 段错误、脏数据、一切正常 等情况,由于这类错误具有隐藏性、潜伏性、随机性,所以它比空指针的危害更大。
2.2 如何避免野指针产生危害
由于野指针无法判断,所以只能不制造野指针才能避免使用野指针。
1、定义指针变量初始化。
2、不返回局部变量的地址。
3、当堆内存释放后,与它配合的指针变量要及时的赋值为NULL。
3.指针解引用
3.1解引用:
*指针变量; // 根据指针变量中存储的内存地址去访问对应的内存块,具体访问多少个字节,由指针变量的类型决定,如果之前赋值的是非法的内存地址,此时会出现段错误。
int num;
int* p = #
*p <=> num; // *p 等价于 num
3.2指针解引用时产生段错误的原因:
1、指针变量中存储的内存地址是非法的,也就是不在map文件的内存范围内。
2、指针变量存储的是text内存段的地址,并尝试修改该内存段的内容。
3、指针变量存储NULL地址,空指针只要解引用就会产生段错误。