- 首先我门回顾一下指针的步长和大小
在64位平台下地址是16位16进制数,转化为二进制数是64位二进制数,也就是8个字节的大小
指针的进阶
目录
- 字符指针
- 指针数组
- 数组指针
- 函数指针
- 指针的安全问题
内容
1.字符指针
我们用数组的方式对p内容的数据进行的修改,发现arr中的数据同样被修改,取数的方式可以跟数组一样用 [ ]符号取,也可以用*p++来遍历指向的数据。这边这个例子表达出一级指针可以同一维数组一样去遍历,当然要注意指向数组的边界,不要越界访问,从而造成野指针的问题,这个往后再讲。既然指针可以像数组一样那他们之间是不是完全相同呢,答案肯定是不一样的往下面看
之后我们再对指针p指向的数据进行修改让我们来看看现象
我们可以发现编译器直接就报错,因为创建一个数组是在栈上给出一块连续的空间,并将数据放入这块空间中去。而
这个操作,后面跟着的是字符常量,常量是不可进行修改的,也就是只读状态,而数组中的数据既可以读也可以写,这是他们之间的区别,当然也是其中的一个区别。指针的用法是C语言的一个亮点,当然也是一个难点。
2.指针数组
首先指针数组是什么呢,是数组?,还是指针?这边我们来辨认一下
首先我们要知道*运算符的优先级非常低
* 取值运算符的优先级比[] () . -> ++ --等运算符的优先级低
这边主要注意的是同[]运算符进行比较
int *p1[5];
int (*p2)[5];
因为优先级的关系int *p1[5] p1首先是同[ ]结合是数组,那p1就是数组,是个什么样的数组呢,再同*结合是一个指针数组。同理来判断一下int (*p2)[5], 因为p2在()里面先同*运算符进行结合是一个指针,(*p2)再同[5]进行结合是一个数组指针
指针的判断方式都是根据这样来判断的。
指针变量可以用来存储一个内存地址,数组可以用来存储一组相同类型的数据,那么,如果我们需要存储多个相同类型的变量的地址,应该用什么呢? 答案就是指针数组,存一组相同类型变量的地址。
首先定义一个指针数组arr存入四个字符串的地址,在用数组的方式取出数据,数据的格式为%p
得到的是h的首地址和w的首地址。其实就是相当于我定义四个char*类型的指针 p1 p2 p3
p4分别指向hello,world,shannxi,和xian然后将四个指针放入数组arr中去,用数组arr取存放指针p1,p2,p3和p4.
3.数组指针
前面我们知道了怎么去辨认是否为指针数组还是数组指针,那数组指针到底是用来存放什么的呢
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int(*p)[10]=&arr;
()优先级高,说明p是指针,指向一个整型的一维数组。这个一维数组的长度是10, 的步长为10。当p+1时,p指针会跨过n个整型数据的长度,从这里开始p的步长就是arr整个数组的大小了。也就是40个字节。VScode上直接用int(*p)[10]=arr;直接用数组名来代替,但是意义是不同的。
4.函数指针
函数指针
函数指针顾名思义是指向函数的指针,将函数的地址赋值给指针。函数指针的定义方式如上图,为指向函数的返回类型void,参数的类型int*,指针p的类型为void(*)(int*),当函数为计算两数之和时,函数指针的定义为什么呢。如下图,
计算出结果为 7;当然赋值给函数指针时也可以用∑
5.指针的安全问题
首先指针的安全问题有三个方面
1.在你定义一个指针并且没有对该指针进行初始化时,直接对其修改会发生什么呢,如下图:
这边直接就编译不通过,直接就把错,为什么呢,未初始化的指针变量,系统会随机给指针p一个地址,这样你在不知道那块地址中存储的数据是啥就可以随意去修改这个数据,这样就非法去访问内存。这个指针也被称为野指针。要避免这样的情况我们可以在初始化指针的时候给指针一个空地址(NULL);之后再给指针赋值。
2.定义一个10个int大小的数组,如图
这边结果任然是可以算出来的,这样我们是不是可以随意的去修改内存中的数据呢
如图:
直接报出了 Run-Time Check Failure #2 - Stack around the variable 'arr' was corrupted.出现这样错误的原因是什么呢
说明我们不可以随意的去修改内存中存储的数据,这边我们是访问并修改了数组之外的数据导致数组越界访问。为了防止这个问题的出现我们需要严格的检查数组的边界。
3.当指针指向的空间已经被释放时如图
我们发现,在得到a的地址时数据第一次打印时得到的数据是a的数据,但当我们记过一段代码后,发现p地址中的数据发生了改变,再次打印还是得到随机数,这里我们来分析一下,在一开始我们在主函数中定义了指针p并且将函数test()的返回值的地址给了指针p,进入函数test中,定义了一个int类型的a变量,在出了test函数时会对函数的空间进行释放,这时变量a已经被释放,指针p拿到的仅仅是一个已经被释放的地址,当然内存中也会保留一次a的数据,在代码的继续运行时,p得到的地址就已经归内存管理。这时我们在对这个空间进行访问其实就是对空间的非法访问。
当然还有其他的问题比如在动态内存中对1块地址空间进行重复的释放,等等
解决的办法:
①在定义指针时将指针初始化为NULL;
② 小心数组的越界访问;
③对动态空间释放后将指针置为NULL;
④不要将函数中定义的变量的地址返回给指针;
⑤在对指针使用之前检查其有效性。