程序在调试时,可能会报“写入位置0xcccccccc 时发生访问冲突”,或者“写入位置0xcdcdcdcd 时发生访问冲突”,这些问题可能是由于使用了未初始化的指针引起的。
先抛出例子:
使用类间组合关系解释问题。
class Name
{
public:
Name(){}
~Name(){}
void GetName()
{
szName= "shabi";
cout<< " Name is:"<<szName;
}
private:
char*szName;
};
class MyTest
{
public:
MyTest(){}
~MyTest(){}
void Show()
{
test->GetName();
}
private:
Name*test;
};
int main()
{
MyTest acPtr;
acPtr.Show();
return 0;
}
注:这是一个有问题的程序,即会出现写入位置0xcdcdcdcd、0xcccccccc或0x00000000 时发生访问冲突,视编译器而定。
指针未初始化而使用一般有两种情况:
第一种发生在类的对象上。一定一定要记住的是,对象的本质就是一块内存,这块内存中的数据一般就是私有成员变量,而成员函数的本质就用来改变该内存的值或状态的。在上面例子中,定义了MyTest对象acPtr,也就是开辟了一块内存空间,我们可以通过对象名acPtr来找到这块内存,并且这个内存中有四个字节的空间用来保存*test这个指针的值。但是,问题就出在这,当我们定义这个对象时,编译器只是预留了四个字节的空间来保存指针的值,而这四个字节的空间并没有被赋值。来点题外话,这个时候编译发现存在没有初始化的指针,因此就会对该内存赋值0xcdcdcdcd或者0xcccccccc,体现在程序中就是“屯屯屯屯……”和“烫烫烫烫……",另外,如果是将指针设为空指针,即为指针赋值NULL,出现错误时是0x00000000,而在跳出的错误对话框中的错误指示便是0xcdcdcdcd、0xcccccccc、0x00000000这三个地址,反正都是指针为初始化。目的是为了能够让人一目了然的知道该问题是因为指针没有被初始化。回到问题上来,此时acPtr的*test成员没有指向任何一块内存,当执行test->GetName();时,传递给GetName()的this指针也是一个未初始化的,上面阐述过成员函数的本质就用来改变该内存的值或状态的。这时传入一个未初始化的this指针,当GetName函数内部的程序语句要改变this指向的内存时,由于this是未初始化的,因此,计算机当然不知道要改变哪一块内存,只有报错了,报出”非法读写内存操作“或者”违规的内存存取“。当然,如果将例子MyTest类中私有成员变量改为Name test;那么当构造acPty这个对象时,MyTest的构造函数会调用Name类的构造函数来构造test成员对象,因此,test就是一块具体的内存空间,其后的调用自然都能够成功。
第二种情况发生于将一个未初始化的指针当做形参传递给函数或使用为初始化的局部指针。原理一样,只要知道程序语句的本质就是用来改变内存值或者内存状态就可以理解。