书接上回https://blog.csdn.net/xiaogy2023/article/details/140051957?spm=1001.2014.3001.5502
目录
6.2.3在使用指针变量之前先检查其有效性,如果不再使用的指针变量,及时置NULL。
免责申明(dog:
以下是我对指针的学习和片面的见解,有问题可以在评论区告诉我,我会改的(手动比心)。
五.指针运算
5.1指针+-整数
我们上一章有讲过,因为数组在内存中是连续存放的,所以我们可以通过首元素地址来找到数组后面的数
*(a+1)找到的是1,*(a+2)找到的是2,通过这个程序我们知道p(地址)+i(整数)等于步长为i*sizeof(int)(这边这个int是指针变量存放地址指向的对象的类型)。
5.2指数-指数
指针-指针可以用于求数组的元素个数
可以看着函数图理解。
5.3指针的关系运算
六.野指针
概念:是指指针变量指向的位置是未知的、随机的、不正确的。
6.1野指针生成的原因
6.1.1指针未初始化
当指针变量未初始化时存放的地址是随机值。
6.1.2访问越界
可以看到当指针超过数组初始化最后一个元素,还在向后访问,那么这个指针变量p就为野指针。
6.1.3指针指向的空间释放
当我们用指针接收函数中创建的值的地址,当函数结束时内存收回了函数的空间也包括创建的变量,那么指针变量p就是一个野指针。
6.2如何避免野指针
6.2.1指针初始化
当你明确指针指向哪里那就直接赋值那个地址,如果不知道或者用完了就可以给指针赋值NULL。
那么什么是NULL呢?
NULL是c语言中定义的一个标识符常量,值是0,地址也是0,这个地址无法使用,读写该地址会报错
6.2.2避免指针越界
要清楚一个程序申请了那些空间,指针只能访问那些空间,不能超出其范围,一但超出就是越界。
6.2.3在使用指针变量之前先检查其有效性,如果不再使用的指针变量,及时置NULL。
为了防止访问到野指针所以赋值为了NULL,当访问到了NULL时就会报错,他好过访问到随机值后产生未知的后果。
七.assert断言
assert是一个由头文件为<assert.h>定义的一个宏叫assert,它的作用可以判断某个条件是否正确,如果条件判断为假就会报错中止,所以这个宏也叫做断言。
代码格式:
图中代码是在判断指针变量p是否为NULL,如果p为NULL判断为假就会报错,如果p不为NULL为真就会继续代码啥都不会发生。
举个栗子:
已知p赋值为NULL,assert判断为假所以报错了。
assert的报错会将你错误的位置信息给报出来,这样可以方便我们快速的定位到错误。
assert的好处还是挺多的,不但可以快速定位到错误位置,还可以“两键”开关,当我们的程序已经完成了调试那么就可以将assert关掉。
那么如何关掉呢?
在头文件#include<assert.h>之前定以一个宏#define NDEBUG,这样就可以将程序中所有的assert关掉
如果程序又出现了问题那么就可以将NDEBUG注释掉,再次打开assert的使用。
八.指针的使用和传址调用
8.1strlen的功能模仿函数
strlen的功能是计算字符串长度,计算\0之前的字符个数。
函数原型如下:
思路:
首先遍历字符串如果不为\0就计数器加一,直到碰到\0。
因为\0也是0所以我将其设置为判断条件,然后每次判断一个数count就加1最后结束将count的数量返回给len,就得出了字符串的长度。
8.2传值调用和传址调用
学了这么多,指针我该怎么运用呢,什么问题我只能用指针呢?
举个栗子:
我们想利用一个函数,将传进进去的两个变量里面的值交换一下位置。
我们可以看到,我们运用函数调换a和b的值,看似调换其实没有。
我们知道调用函数时我们传的参数是实参,函数接收的却是形参,而形参是实参的一份临时的拷贝,形参的更改并不会影响实参,所以当程序走完a和b并没有交换。
当我们使用函数时,直接以变量本身为函数参数,这种调用函数的方式我们从以前的知识和刚刚的图片我们可以知道叫:传值调用
那么我们来浅浅的改一下:
我们可以看到调用函数时我们传参的是a和b的地址,然后函数用指针变量来接收,那么指针变量中接收的就是地址的一份拷贝,我们直接通过地址找到a和b中的值并进行交换。
这种将变量地址传输给函数进行运算的叫做:传址调用。