设为首页 加入收藏

TOP

一文读懂野指针(一)
2023-07-23 13:32:05 】 浏览:123
Tags:文读懂

一、引子

        我们都知道对指针( Pointer)的操作,实际上是对计算机内存地址的操作,通过访问内存地址实现间接访问该地址中保存的数据。其实就是CPU的寻址方式中的间接寻址。简单概括正常使用指针时的3个步骤为:

  • 定义指针变量
  • 绑定指针即给指针变量赋值
  • 解引用即间接访问目标变量
    通过一个简单的例子来看这3个步骤的实现:
1 int a = 5;
2 //定义指针变量p
3 int *p; 4 //绑定指针,就是给指针变量赋值,指向另一个变量a(指针的用途就是指向别的变量) 5 p = &a; 6 //将6放入p所指向的那个变量的空间中,这里就是a的空间 7 *p = 6;

        可以看出,在定义指针变量p时,未初始化p,这个时候的p为随机值,此时解引用p是没有意义的,内存随机值的空间是否有效我们也不得而知。

        绑定指针就是将变量a的地址赋值给指针变量p,此时p就有了意义,明确了内存中访问的具体空间位置,p是指向变量a的空间的,变量a是有具体内容的,因此指针必须给它赋值才能解引用它。

        给指针变量p赋值实际上是在变量a前加一个“&”符号,这个符号是取地址符,&a就是指变量a的地址,编译器在给每个变量分配出内存空间,并将a与这块的内存空间地址绑定。这个地址只有编译器知道,而程序员并不知道编译器随机给这段空间分配什么随机地址值。程序员要获取或操作这个地址时,就需要使用取地址符。

        由上述分析看来,给p赋予了变量a地址的值是一个合法的,在内存中明确的地址值,这个值是受控的,同时通过访问指针间接访问该地址中保存的数据也是受控的,p就是一个正常的指针。

        相反,如果指针指向了内存中不可用的区域,或者是指针的值是非法的随机值也就是非正常内存地址,那么这个指针就是不受控的,同时通过访问指针间接访问该地址中保存的数据也是不受控的,同时是不可知的,此时这个指针就是野指针(Wild Pointer)

二、需要明确的一点

        野指针不同于空指针,所谓空指针,是给指针变量赋NULL值,即:

1 int *p = NULL;

        所谓NULL值在C/C++中定义为:

1 #ifdef __cplusplus         // 定义这个符号表示当前是C++环境中
2 #define NULL 0             // 在C++中NULL为0
3 #else
4 #define NULL (void *) 0    // 在C中的NULL是强制类型转换为void *的0
5 #endif

        可以看出,给p赋值NULL值也就是让p指向空地址。在不同的系统中,NULL并不意味等于0,也有系统会使用地址0,而将NULL定义为其他值,所以不要把NULL和0等同起来。你可以将NULL通俗理解为是空值,也就是指向一个不被使用的地址,在大多数系统中,都将0作为不被使用的地址,因此就有了这样的定义,C或者C++编译器保证这个空值不会是任何对象的地址。

        void *表示的是“无类型指针”,可以指向任何数据类型,在这里void指针与空指针NULL区别:NULL说明指针不指向任何数据,是“空的”;而void指针实实在在地指向一块内存,只是不知道这块内存中是什么类型的数据。

        空指针的值是受控的,但并不是有意义的,我们是将指针指向了0地址,这个0地址就是作为内存中的一个特殊地址,因此空指针是一个对任何指针类型都合法的指针,但并不是合理的指针,指针变量具有空指针值,表示它处于闲置状态,没有指向任何有意义的内容。我们需要在让空指针真正指向了一块有意义的内存后,我们才能对它取内容。即:

1 int a = 5;
2 int *p = NULL; 3 p = &a;

         NULL指针并没有危害,可以使用if语句来判断是否为NULL。

三、一些典型的error

        我们要知道单纯的从语言层面无法判断一个指针所保存的地址是否是合法的,等到程序运行起来,配合硬件的内存实际地址,才能发现指针指向的地址是否是你想要让它指向的合理空间地址。在日常编码过程中有一些导致野指针或者内存溢出的错误编码方式:

1、指针变量未初始化

        任何指针在被创建的时候,不会自动变成NULL指针,因此指针的值是一个随机值。这时候去解引用就是去访问这个地址不确定的变量,所以结果是不可知的。

1 void main()
2 { 3 char* p; 4 *p = 6; //错误 5 }

2、使用了悬垂指针

        在C或者C++中使用malloc或者new申请内存使用后,指针已经free或者delete了,没有置为NULL,此时的指针是一个悬垂指针。

        free和delete只是把指针所指的内存给释放掉,并不会改变相关的指针的值。这个指针实际仍然指向内存中相同位置即其地址仍然不变,甚至该位置仍然可以被读写,只不过这时候该内存区域完全不可控即该地址对应的内存是垃圾,悬垂指针会让人误以为是个合法的指针。

1 void main()
2 { 3 char* p = (char *) malloc(10); 4  strcpy(p, “abc”); 5 free(p); //p所指的内存被释放,但是p所指的地址仍然不变 6 strcpy(p, “def”); // 错误 7 }

3、返回栈内存指针或引用

        在函数内部定义的局部指针变量或者局部引用变量不能作为函数的返回值,因为该局部变量的作用域范围在函数内部,该函数在被调用时,由于局部指针变量或者引用已经被销毁,因此调用时该内存区域的内容已经发生了变化,再操作该内存区域就没有具体的意义。

 1 char* fun1()
 2 { 3 char* p = "hello"; 4 return p; 5 } 6 7 char* fun2() 8 { 9 ch
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇一文搞懂蓝牙模块各种工作模式 下一篇痞子衡嵌入式:存储器大厂Micron..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目