上篇文章我简单介绍了下基本的指针,这一篇我会介绍一些进阶的知识。
一、void * 的指针:
在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进⾏指针的±整数和解引⽤的运算。一般当我们需要访问这个指针所指向的数据时,需要进行强制转换。
那么void*的指针的主要用途是什么呢?–(在函数参数的部分,⽤来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果。使得⼀个函数来处理多种类型的数据。)
二、const的介绍:
const就是一个限制变量的修改的关键字,变量是可以修改的;
在指针中,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量。但是如果我们希望⼀个变量加上⼀些限制,不能被修改,怎么做呢?这就是const的作⽤。
虽然上面我们成功的对其进行了限制,但要是我们取n的地址然后,通过指针变量来间接改变n是可以做到的,例如:
在这里n的值被改变了,如果p拿到n的地址就能修改n,这样就打破了const的限制,这是不合理的,所以应该让p拿到n的地址也不能修改n,那接下来怎么做呢?
—const修饰指针变量—
const修饰指针变量时会有两种形式,一种是在 * 的左边,一种是在 *的右边,它们之间是有着明显不同的,我这里先给出结论:
1、const如果放在 * 的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。
2、const如果放在 * 的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。
三、指针的运算:
指针的运算有三种:
1、指针±整数;
例如:数组在内存中是连续存放的,那我们就可以通过±整数的办法来访问数组成员。
在这里插入图片描述
2、指针-指针(同类型);
它的运算结果是两个指针所指向元素之间的个数;
那么通过指针相减的方式是不是可以模拟实现strlen对吧?如果有需求可以私信我。
3、指针的关系运算;
五、野指针:
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
常见的野指针有三种:
1、指针未初始化:
2、指针的越界访问:
3、指针所指向的空间被释放掉:
这里的n只出现在函数test中,当使用完n这个变量后,n的值会被释放掉,虽然返回了n的地址,但是不会打印出n的值。
六、那么我们如何避免野指针的出现呢?
1、如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL。NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址会报错。
2、⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问。
3、指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性。
4、 避免返回局部变量的地址。
七、assert断言。
⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。assert.h 头⽂件定义了宏 assert() 。
它的用法即assert(p!=NULL),这段代码就是来判断p是否指向空指针,如果不等于空指针会继续运行,否则就会停止运行,并打印出错误信息。
如果已经确认程序没有问题,不需要再做断⾔,就在 #include <assert.h> 语句的前⾯,定义⼀个宏 NDEBUG 。
然后,重新编译程序,编译器就会禁⽤⽂件中所有的 assert() 语句。如果程序⼜出现问题,可以移除这条 #define NDBUG 指令(或者把它注释掉),再次编译,这样就重新启⽤了 assert() 语句。
⼀般我们可以在 Debug 中使⽤,在 Release 版本中选择禁⽤ assert 就⾏,在 VS 这样的集成开发环境中,在 Release 版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题,在 Release 版本不影响⽤⼾使⽤时程序的效率。
这一篇博客介绍了一些简单指针的用法,以及有关的知识,下一篇会介绍一些进阶的用法。