目录
过早退出是一切失败的根源。——高德纳
1.什么是指针
机器内存
大多数现代计算机将内存分割为字节,每个字节存储八个bit位的信息。
- 每个字节都有唯一的地址,用来和内存其它字节相区别。
32位机器
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生一个电信号正电/负电(1/0)
- 指针的大小在32位平台是4个字节,而指针的地址为4个字节的首地址
64位机器
-
指针的大小在64位平台是8个字节,指针的地址为8个字节的首地址
2.取地址运算符和解引用操作
取地址运算符
&:为了找到变量的地址,使用的运算符
解引用操作
*:为了获取对指针所指向对象的访问,使用的运算符
int a = 10;
int* p = &a;
*p = 20;
3.指针和指针类型
指针就是指向一块空间的变量,如下:
int a = 10;
int* ptr = &a;
ptr即为指针,ptr指向的空间为变量a的空间。我们可以利用指针ptr来修改变量a的值或者做其他事情。
指针类型具有一定意义:
1.指针类型决定了指针访问空间的能力,进行解引用操作的权限有多大,访问几个字节
int* :访问4个字节,char* :访问1个字节,double* :访问8个字节
2.指针类型决定了指针的步长(向前-,向后+,都多大距离)
int* 指针+1,跳过一个整形,向后走4个字节
char* 指针+1,跳过一个字节,向后走1个字节
4.野指针
概念:指针指向的位置是不可知的(随机的、不正确的,没有明确限制的)
野指针成因
-
指针未初始化
int* p;//p就是野指针 p=20;
-
越界访问
int main() { int arr[] = { 1,2,3,4,5 }; int* a = arr; for (int i = 0; i <= 5; i++) { *(a + i) = 0;//当i=5时,访问超出范围,称为野指针 } return 0; }
-
指针指向的空间释放了
int* text() { int a = 20; int* b1 = &a; return b1; } int main() { int arr[] = { 1,2,3,4,5 }; int* a = arr; int* b = text();//此处函数内的b1指针变量已经释放 return 0; }
野指针的危害
我们已经知道,野指针是指向一个不可知的地址的指针,那它的危害分三种情况:
1. 指向不可访问地址
危害:触发段错误
2.指向一个可用的,但没有明确意义的空间
危害:程序可以正常运行,这时我们通常认为程序没有什么问题,但这个指针时刻是一颗雷,但程序用到该指针指向的空间时就有可能会爆炸。
3.指向一个可用的。而且正在被使用的空间
危害:如果我们对该指针解引用并进行修改,这块正在使用当中的空间变量忽然被改变,就会对程序的运行产生影响。通常这样的程序会造成程序的崩溃,或者数据被破坏。
如何避免野指针
-
指针初始化
int a=10; int* p=&a;//明确初始化 int* p=NULL;//NULL - 0,就是初始化指针
-
小心指针越界
-
指针指向的空间释放后,及时置空NULL
free();
-
避免返回局部变量的地址
-
指针使用之前检查有效性
- 空指针无法直接付值
int* p=NULL;
p=20;//是错误的
5.指针运算
指针+-整数
int main()
{
int arr[] = { 1,2,3,4,5,6,7 };
int* p = arr;
for (int i = 0; i < 7; i++)
{
printf("%d ", *p);
p += 1;
}
return 0;
}
指针加减整数,产生指针指向元素前后整数位的指针。
即p+3,表示为arr[2+3]
p-2,表示为arr[2-2]。
指针-指针
计算指针之间的元素个数(用数组元素的个数来衡量)
两指针之间必须为同一块连续的空间,否则无法确定
用处:
int main()
{
int arr[] = { 1,2,3,4,5,6,7 };
int a = &arr[6] - &arr[0];
printf("%d", a);
return 0;
}
指针比较
条件:使用关系运算符和判断运算符进行比较,只有在两个指针指向同一数组时,用关系运算符进行的指针比较才用意义。
int* a=arr[0];
int* b=arr[5];
a>=b的值为0;
a<=b的值为1.
指针的关系运算
比较大小
指针比较标准规定
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但不允许与指向第一个元素之前的那个内存位置的指针进行比较。
不可以使用p1进行比较,可以使用p2进行比较
6.指针和数组
-
数组名是什么
首元素地址
但是有两个意外:
-
&arr----&数组名----取地址数组名时----此时数组名不是首元素地址,而是表示整个数组的地址
int main()
{
int arr[10] = { 0 };
printf("%d ", arr);
printf("%d\n", arr + 1);
printf("%d ", &arr[0]);
printf("%d\n", &arr[0] + 1);
printf("%d ", &arr);
printf("%d\n", &arr + 1);
return 0;
}
2.sizeof(arr)---sizeof(数组名)-----数组名表示的是整个数组----sizeof(数组名)计算的是整个数组的大小
int arr[10] = {0};
printf("%d",sizeof(arr));//打印为40
7.二级指针
int*中int表示int*前面指向的对象为int类型,以此可以联想二级指针‘
8.指针数组
存放地址的数组