c语言野指针举例,C语言野指针 (转载CSDN)

“野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。

“野指针”的成因主要有两种:

(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如

char *p = NULL;

char *str = (char *) malloc(100);

(2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。参见7.5节。

别看free和delete的名字恶狠狠的(尤其是delete),它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。

用调试器跟踪示例7-5,发现指针p被free以后其地址仍然不变(非NULL),只是该地址对应的内存是垃圾,p成了“野指针”。如果此时不把p设置为NULL,会让人误以为p是个合法的指针。

如果程序比较长,我们有时记不住p所指的内存是否已经被释放,在继续使用p之前,通常会用语句if (p !=

NULL)进行防错处理。很遗憾,此时if语句起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。

char *p = (char *) malloc(100);

strcpy(p, “hello”);

free(p); // p 所指的内存被释放,但是p所指的地址仍然不变

if(p !=

NULL) // 没有起到防错作用

{

strcpy(p,

“world”); // 出错

}

示例7-5 p成为野指针

(3)指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:

class A

{ public:

void Func(void){ cout << “Func of

class A” << endl; }

};

void Test(void)

{

A *p;

{

A a;

p =

&a; // 注意 a 的生命期

}

p->Func(); // p是“野指针”

}

函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。

Lufer 发表于2006-01-12 7:15 AM IP:

222.183.87.*

函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。

TO:楼主

我认为不是跟编译器有关,而是p指向的内存区域的内容没有改变,所以仍然可以调用func函数,这样存在潜在的危险,但是你的程序中没有表现出来。即使表现出来时,运行也不会有错,只是逻辑上会出错。楼主觉得呢?

leiXure 发表于2006-01-12 9:20 AM IP: 211.162.235.*

同意Lufer

稍稍改一下你的类就会发现问题

class A

{

public:

void Func(void) { cout << m_msg

<< endl; }

private:

std::string m_msg;

};

一凡 发表于2006-01-12 9:37 AM IP:

#define SafeFree(p) do {if(p) {free(p);p=NULL;}} while(0)

Rayz 发表于2006-01-12 10:16 AM IP:

219.142.170.*

我也举3个例子,分别属于三种情况

1.

class1 * p;

if(p == NULL)

{

P = new class1;

}

else

{

p->Fun1(); //崩溃

}

2.

class1 * p = new class1;

//do sth.... then delete

delete p; //虽然delete,但指针仍不会为空,此时应 P

//P = NULL;

if(p == NULL)

{

P = new class1;

}

p->Fun1(); //崩溃

3. class1

{

public:

void Fun1();

void Fun2();

private:

class1 * p;

}

void class1::Fun1()

{

if(this->p) //其实我想写 if(this == p) ,笔误,呵呵

{

this->Fun2(); //很明显,容易崩溃,呵呵

}

}

fengqingyang2008 发表于2006-01-12 2:48

PM IP: 61.242.107.*

p->Func();

这个是不会出错的,因为你的函数并没有访问A这个类的任何一个数据成员或虚函数指针。

A* ptr=0;

ptr->Func();

这样也是不会出错的

C语言中delete与delete []的不同

下面的语句有什么错?

string *stringarray = new string[100];

...

delete stringarray;

一切好象都井然有序——一个new对应着一个delete——然而却隐藏着很大的错误:程序的运行情况将是不可预测的。至少,stringarray指向的100个string对象中的99个不会被正确地摧毁,因为他们的析构函数永远不会被调用。

用new的时候会发生两件事。首先,内存被分配,然后,为被分配的内存调用一个或多个构造函数。用delete的时候,也有两件事发生:首先,为将被释放

的内存调用一个或多个析构函数,然后,释放内存。对于

delete来说会有这样一个重要的问题:内存中有多少个对象要被删除?答案决定了将有多少个析构函数会被调用。

这个问题简单来说就是:要被删除的指针指向的是单个对象呢,还是对象数组?这只有你来告诉delete。如果你在用delete时没用括号,delete就会认为指向的是单个对象,否则,它就会认为指向的是一个数组:

string *stringptr1 = new string;

string *stringptr2 = new string[100];

...

delete stringptr1;// 删除一个对象

delete [] stringptr2;// 删除对象数组

如果你在stringptr1前加了"[]"会怎样呢?答案是:那将是不可预测的;如果你没在stringptr2前没加上"[]"又会怎样呢?答案也

是:不可预测。而且对于象int这样的固定类型来说,结果也是不可预测的,即使这样的类型没有析构函数。所以,解决这类问题的规则很简单:如果你调用

new时用了[],调用delete时也要用[]。如果调用new时没有用[],那调用delete时也不要用[]。

在写一个包含指针数据成员,并且提供多个构造函数的类时,牢记这一规则尤其重要。因为这样的话,你就必须在所有初始化指针成员的构造函数里采用相同的new的形式。否则,析构函数里将采用什么形式的delete呢?

这个规则对喜欢用typedef的人来说也很重要,因为写typedef的程序员必须告诉别人,用new创建了一个typedef定义的类型的对象后,该用什么形式的delete来删除。举例如下:

typedef string addresslines[4];//一个人的地址,共4行,每行一个string

//因为addresslines是个数组,使用new:

string *pal = new addresslines;// 注意"new addresslines"返回string*,

// "new string[4]"返回的一样

delete时必须以数组形式与之对应:

delete pal;// 错误!

delete [] pal;// 正确

为了避免混乱,最好杜绝对数组类型用typedefs。这其实很容易,因为标准c++库包含有stirng和vector模板,使用他们将会使对数组的需

求减少到几乎零。举例来说,addresslines可以定义为一个字符串(string)的向量(vector),即addresslines可定义为

vector类型。

new对应delete而new[]对应的是delete[]

释放空间的作用上基本上一样,但是delete[]和delete调用的析构函数的次数是不一样的,delete只调用一次,而delete[]会根据new[]创建的对象数调用析构函数。

new[] 分配内存的时候在前端多分配了一些字节来保存数组长度,因为 delete[] 需要利用这些信息逐个调用数组元素的

destructor.

vc6 DEBUG 版本下 new[] 分配的内存用 delete 清除就会出 runtime exception。

对于基本数据类型,这也许没有任何问题,但是delete与delete[]的区别在于调用析构函数的次数是不同的(前者只有一次)。但对于类类型,就需要用delete[]

与new[]对应

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值