野指针(悬挂指针)-尊龙官方平台

野指针(悬挂指针)

el/2024/3/25 17:09:19

野指针(悬挂指针)


野指针:一个指针变量指向一个错误的地址,即,这个指针变量中存着的值是一个污数据,是无效的,错误的,无用的。
野指针即悬挂指针。

野指针的核心概念:一个指针变量指向的空间是不可访问的,也不应该被指针操作者访问,即,指针变量中的数据是 污数据

出现野指针的情况:

1.指针变量在定义时未初始化;

2.指针指向的对象或空间已经被delete或free掉了,并且未及时置指针变量值为null;

3.指针指向的对象在此作用域中已无效(通常由于此对象已被释放)。

针对第一种情况:

指针变量如果是在栈上(局部)创建,而不是在堆上(全局)创建,那么其值通常是不可靠的,极有可能其值不为null,而是指向一个位置的内存空间,对这样的指针进行操作是完全无意义的,且可能破坏某些重要的数据信息,毕竟,你不知道它到底指向哪里;

#include using namespace std;int main(int argc, char* argv[])
{void *p;cout<

怎么会是0?这种情况可能是编译器表现出来的,常使人迷惑。

请谨记,栈上声明的指针,若不初始化,其值都是不可靠的,极有可能不是null,任何时候也不要依赖于编译器去做这件事情。

针对第二种情况:

#include using namespace std;int main(int argc, char* argv[])
{int *p = (int *)malloc(20);*(p) = 0;*(p 1) = 1;*(p 2) = 2;*(p 3) = 3;*(p 4) = 4;for (int i = 0; i<5; i  )cout<<*(p i)<

p指向的空间是malloc出来的,在free后,其指向的空间,已被操作系统认为是可被重用的空间,可能下一次malloc,还是这个地址开始的空间。

在free这个空间之后,这个空间的值就得不到了保证,随时可能被别的进程所操作(读/写),故此处所存的数据也不再有效,不可靠。

p这个时候,也是一种野指针。

delete同理,不再赘述。

注:

对于c ,一个类中可以有成员变量是一个指针,但是需要注意,在对象之间复制和赋值时可能出现隐患—请看下面的几个小例子:

【例1】

#include using namespace std;class a
{
public:a():p(null){}~a(){free(p);}void mymalloc();void myfree();void setval(int v);int getval();
private:int *p;
};void a::mymalloc()
{p = (int *)malloc(sizeof(int)*1);
}void a::myfree()
{free(p);
}void a::setval(int v)
{*p = v;
}int a::getval()
{return *p;
}int main(int argc, char* argv[])
{a obj1;obj1.mymalloc();obj1.setval(6);cout<<"obj1 val is :"<

编译后运行。

结果报错:

obj1 val is :6
obj2 val is :6
*** glibc detected *** ./main: double free or corruption (fasttop): 0x0000000017361010 ***
======= backtrace: =========
/lib64/libc.so.6[0x31c987174f]
/lib64/libc.so.6(cfree 0x4b)[0x31c987597b]
./main(__gxx_personality_v0 0x2f6)[0x400b26]
./main(__gxx_personality_v0 0x283)[0x400ab3]
/lib64/libc.so.6(__libc_start_main 0xf4)[0x31c981d9c4]
./main(__gxx_personality_v0 0x49)[0x400879]
======= memory map: ========
00400000-00401000 r-xp 00000000 fd:00 4243371                            /home/mytmp/20170330/main
00601000-00602000 rw-p 00001000 fd:00 4243371                            /home/mytmp/20170330/main
17361000-17382000 rw-p 17361000 00:00 0                                  [heap]
31c9000000-31c901c000 r-xp 00000000 fd:00 1340605                        /lib64/ld-2.5.so……

./main: double free or corruption

说的很明白了,两次free。

由于obj2是完全由obj1那里复制来的,当然obj2中私有成员变量同obj1中是一样的,指向同一片malloc出来的内存空间。

在main函数结束时,两个a对象将会被析构,在析构中free这个指针时,第一个析构没啥问题,第二个析构可就出问题了:

free一个null,几次都ok,但是你不能可一个具体的值free呀。

很坑吧。。。

同样需要注意的是,比如:

【例2】

// a类定义同上void myfunction(a a){}int main(int argc, char* argv[])
{a obj1;obj1.mymalloc();obj1.setval(6);cout<<"obj1 val is :"<

额,运行时还报错,同上:

*** glibc detected *** ./main: double free or corruption (fasttop): 0x0000000005c98010 ***

原因在于,传入myfunction时,会复制一个一模一样的对象到myfunction函数栈上,当函数结束时,函数栈上的对象都会自动析构,也就会释放此对象所的空间;
在main函数结束时,欲再一次free,结果同上。

修改方法:

void myfunction(a &a){}

再看看下面的例子:

【例3】

#include using namespace std;class a
{
public:a():p(null){}~a(){free(p);cout<<"deconstructor called"<

会是什么结果呢?为什么会出现这样的结果呢?

总之:在一个类中声明其持有指针,需要谨慎对待,谨慎使用呀!尤其在函数实参形参结合之时。

针对第三种情况:

#include using namespace std;int *p = null;void setp()
{int num = 10;p = #
}int main(int argc, char* argv[])
{setp();cout<

在main中,先调用了setp这个函数,在此函数中定义了局部变量num,注意,此局部变量是在setp这个函数栈上的,当setp调用返回后,num这个变量就会被销毁。

返回到main中,num已不在其作用域中,此时,一个指针变量指向其在栈上的位置,还有意义吗?无意义。

可能有一种情况:输出时还是10,这是由于,系统暂时没有对这块内存操作,但是谁也不能保证系统啥时候操作它,你说呢?


上述三种,基本上是野指针出现的各种成因。

野指针一般不易被发现。

通常大家会使用:

    if (p != null)//do something

这样的条件语句来判断其是否有值来避免操作空指针,但是很明显,其不能防备野指针,野指针有值,但是值确是错误的,无效的。

野指针的解决办法:

通常最终要的一点,也是最核心的一点,就是养成良好的变成习惯,譬如:

    free(p);p = null;

这是最常见的形式,应该尽可能地,当free时,就想起来要置p为null,如同你malloc时就轻微紧张地想起要free,形成一条线。

尽可能地将其作为一种原子操作,即使在java这样的不须太过关心指针的语言中,在对象消亡后,也应该及时地置null,这是一种习惯。

如上,我们可以把它封装成一个宏:

#include using namespace std;#define xfree(ptr) {free(ptr);ptr=null;}int main(int argc, char* argv[])
{int *p = (int *)malloc(20);*(p) = 0;*(p 1) = 1;*(p 2) = 2;*(p 3) = 3;*(p 4) = 4;for (int i = 0; i<5; i  )cout<<*(p i)<

关键在于:
#define xfree(ptr) {free(ptr);ptr=null;}
这是一个宏定义。

注:free一个空指针不会出现问题。(free(null)总是成功的,不出错的。)

再者可以使用智能指针,说白了,智能指针就是一个类,使用引用计数来去“智能地”判断,下次有时间详细总结~


http://www.ngui.cc/el/5127184.html

相关文章

linux配置java环境(jdk)

linux配置java环境(jdk) 首先从oracle尊龙官方平台官网下载jdk安装包: 这里给出oracle尊龙官方平台官网:https://www.oracle.com 在哪里下载应该能找到,这些就不赘述了。 注:下述以“#”开头的为我的注释,非执行语句…

c/c 变量作用域

c/c变量作用域 今天忽然想起作用域的问题,随手试验了下。 代码: #include #include // mark1 int n1; // scope 1 >>>int main() {printf("i:%d\n", n);// mark2int n2;// scope 2 >>>p…

c 中list、deque以及vector对比

c中list、deque以及vector对比 c的容器类包括两大类: 1.顺序存储结构,包括vector、list、deque等等; 2.关联存储结构,包括set、map、multiset等等; 本文主要对比vector、list以及deque这三种顺序存储结构。 注&am…

打擂台排序与冒泡排序(未完)

打擂台排序与冒泡排序 c code: #include #include void print_array(int *array, int n) {int i;for (i0; i

linux下安装valgrind工具

linux下安装valgrind工具 valgrind是一款很优秀的内存泄漏检测工具。 下面介绍如何在linux下安装valgrind。 首先下载安装包到/root目录下(或者其他目录); [rootlocalhost ~]# ll total 7200 -rw-------. 1 root root 2692 apr 10 13:52 a…

简单选择排序(simple select sort)

简单选择排序(simple select sort) 简单选择排序是入门级别的排序算法,算法易懂,实现简单。 假设现在有一个待排序序列,长度是n,要求从小到大排序。 简单选择排序将要进行n-1次外循环(不需要进行…

c/c :sizeof数组与指针

c/c:sizeof数组与指针 在c/c中使用sizeof对数组和指针所得的结果是不一样的。 [例1] #include #include #define safe_free(p) {free(p);pnull;}int main() {char arr[20];char *p (char *)malloc(sizeof(char) * 20);printf("sizeof…

《啊哈!算法》简单桶排序(simple bucket sort)

《啊哈!算法》简单桶排序(simple bucket sort) 首先想想如何简单地排序? 假设我们有5个学生,分数分别是5, 3, 5, 2, 8,满分10分。 由实际可知,分数范围在[0,10],闭区间范围内。 …

linux:subversion服务端安装及配置

linux:subversion服务端安装及配置 环境: centos 7 [rootlocalhost ~]# uname -a linux localhost.localdomain 3.10.0-327.el7.x86_64 #1 smp thu nov 19 22:10:57 utc 2015 x86_64 x86_64 x86_64 gnu/linux [rootlocalhost ~]# which svn /usr/bin/…

linux:subversion客户端安装及配置

linux:subversion客户端安装及配置 注:如果很着急安装,可以直接看第二种方式;如果不着急,还想要体验一把“依赖”的酸爽,可以慢慢看下面的步骤。 环境: centos 6.8: [rootlocalh…
网站地图