指针
指针
1. 指针的作用
- 使程序简洁、紧凑、高效
- 有效地表示复杂的数据结构
- 动态分配内存
- 能直接访问硬件
- 能够方便的处理字符串
- 得到多于一个的函数返回值
2. 指针和指针变量
指针初始化
int main() {
int a = 10;
int * p = &a; // p 是指针变量,p 的内容为 a的地址
printf("&a=%p p=%p &p=%p\n", &a, p, &p);
return 0;
}
3. 指针的目标和解引用
指针指向的内存区域中的数据称为指针的目标
如何通过指针修改指针的目标呢?===> 指针的解引用
int main() {
int a = 10;
int * p = &a;
(*p)++; // 间接地去访问了指针的目标
cout << a << endl; // 11
return 0;
}
关于指针的3种写法:
4. 指针的赋值
0是有效的地址(最小的)
指针的赋值
数组名代表了整个数组的起始地址(也就是a[0]的地址)
int main() {
int a[] = {1, 2, 3};
int * p;
printf("%p %p\n", a, &a[0]);
return 0;
}
5. 空指针
- 不同于没有初始化的指针
int * p, // 没有初始化的指针(这里说的空指针,不是指这个意思)
int * p = &a;
- 在 C 语言中,NULL 本质是:0
#defne NULL (void *)0 // 在 C 中 NULL 是强制类型转换为 void* 的0
Demo
int main() {
int a = 10;
int *p;
int *q = NULL;
printf("p=%p q=%p\n", p, q);
return 0;
}
空指针为什么指向0地址处???2个原因
- 指针如果没有给定初始值,值是不确定的
- 0地址是一个特殊地址,在一般的操作系统中都是不可访问的,如果C语言不按照规矩(不检查是否等于 NULL 就去解引用)写代码直接去解引用就会触发段错误(Segmentation fault)
6. 野指针(Wild)
定义和成因
定义:
- 指针指向的位置是不可知的(随机的,不正确的,没有明确指向的)
- 指向被释放的内存或者没有访问权限的内存的指针(非法访问)
如何造成的:
- 野指针的措误来源就是指针定义了以后没有初始化,也没有赋值(总之就是指针没有明确的指向一个可用的内存空间),然后去解引用。
- 指针越界访问
int main() {
int a[] = {1, 2, 3};
int *p = &a[3]; // 越界
printf("%p\n", p);
return 0;
}
- 指针指向的空间已经释放了
int main() {
int m = 10;
int *p = &m;
int i;
for(i = 0; i < 3; i++){
int t = 0;
p = &t;
t++;
printf("t=%d %p\n", t, p);
}
printf("m:%d %p\n", *p, p); // 指针所指向的空间已经被释放了
*p = 2000;
return 0;
}
危害
- 野指针指向别的变量(指针所指向的那个变量)的地址
- 即指向了一个地址是不确定的变量,去解引用,结果不可知的。
- 段错误
指向不可访问(操作系统不允许访问的敏感地址,如内核空间)的地址,结果是触发段错误 - 程序错误被掩盖
指向一个可用的、而目没什么特别意义的空间(譬如我们曾经使用过但是已经不用的空间),这时候程序运行不会出错,也不会对当前程序造成损害这种情况下会掩盖你的程序错误,让你以为程序没问题,其实问题是非常严重的 - 程序出现离奇错误
指向了一个可用的空间,而且这个空间其实在程序中正在被使用(譬如说是程序的一个变量x),那么野指针的解引用就会刚好修改这个变量的值,导致这个变量莫名其妙的被改变,程序出现离奇的错误。一般最终都会导致程序崩溃,或者数据被损害