近日JMcat写C++的数据结构模板,遇到了若干指针的问题……
首先需要说明的是,JMcat非常讨厌指针,以前做ACM之类的程序题,凡是遇到指针的问题,统统绕道而行。因为ACM类题目的数据范围比较固定,用数组模拟常常能达到比较好的效果。
例如,我要写一个单链表,可以如此:
int data[10000],next[10000];
其中data用来存一个结点的数据,next用来表示指向的下一个结点的数组下标。
再例如我要写一棵二叉树,可以如此:
int data[10000],left[10000],right[10000];
其中data用来存结点数据,left和right分别表示左右孩子结点的数组下标。
因为链表本身是一个结构体,用数组去表示结构体的每一个部分,可以达到同样的目的,并且数组看上去要更直观一些。
但是数组毕竟有它的缺点,就是范围一上来就固定了,所以有时候还是需要用指针来。都说指针是语言中最难的部分,更由于JMcat平时很少使用,所以这天写程序遇到了好多问题。下面分别说一下:
(1)空间申请用malloc,空间释放用free,我一直以为某个指针被free掉了以后,就是NULL了,我可以用NULL来判断它。然而再若干次出错以后,我发现并不是这样的。
准确的说,NULL的含义是#define NULL 0。某个指针被free掉以后,指向了一个莫名的地址,不是NULL。某个指针被赋值成NULL之后,也没有释放空间。它们两个实际上毫无关系。
通过网上查阅了些资料,得到了一个名次——“野指针”。野指针有两种情况,一种是定义了但是没有分配空间,一种是释放了空间。这两种情况的指针都是不可控制的。
为了预防野指针,我采用的一个方法就是在free掉之后再赋值成NULL。
(2)为了避免写过多的函数重载,我用了C++中的模板template <class T>,不得不说这种方法确实很好用,但是用着用着发现问题了,怎么free掉一个结点会提示Heap corruption detected错误呢?JMcat那个迷茫的查啊查,最后发现用了模板的写法和原来有一个区别。
我在链表定义的时候是这样:
struct IntLinkedList
{
int node;
struct IntLinkedList *next;
}
插入函数这样写的:
template <class T1,class T2>
void Insert(T1 &tail, T2 x) //x是要插入的值,插入到tail以后
{
T1 p;
p = (T1)malloc(sizeof(T1));
……
}
好了,发现问题了吗?
我们正常分配空间是这么写的:
struct IntLinkedList *p;
p=(struct IntLinkedList *)malloc(size(struct IntLinkedList));
但是在这里,我们首先要知道T1是什么类型,答案是IntLinkedList *。
一个简单的测试:
cout<<size(struct IntLinkedList)<<endl;
cout<<size(struct IntLinkedList *)<<endl;
答案分别是
8
4
所以问题出在分配空间的问题上,修改之后便解决了。
以上是今天遇到的两个主要问题,和大家分享,当JMcat遇到更多问题,还会回来!
浙公网安备 33010602011771号