为了偏于叙述,我将遇到问题的源代码进行了简化,只保留了出现问题的根本语句。
给出代码:
#include <stdio.h>
#include <stdlib.h>
#define N 100
struct A
{
int a[N];
};
int main()
{
struct A* p;
p = (struct A*)malloc(sizeof(struct A*));
for (unsigned int i = 0;i < N; ++i)
{
p->a[i] = i;
}
for (i = 0;i < N; ++i)
{
printf("%d\t",p->a[i]);
}
free(p);
return 0;
}
首先定义结构体指针,然后进行动态内存的分配。之后是一个循环赋值,一个循环输出。奇怪的问题出现了,如果注释掉了free (p);运行一下,帅气的结果,如下图:
但是毕竟我们毕竟用到了动态内存分配时不是应该回收内存呢?所以去掉对free的注释,再次编译链接运行,一看,结果是没有错,只是多弹出了一个窗口,如下图:
这就奇怪了,既然能够将结果正确的输出,再结合前面能够“正确”输出,我们很容易确定是free出了问题,free(p)应该也是没有问题的,我们给它动态内存分配,现在回收肯定的没有问题的。难道是编译器的问题?
应该不是编译器的问题吧,毕竟VC6.0十几年了依旧风光无限。再来检查检查??
稍微仔细一点的同学都能发现p = (struct A*)malloc(sizeof(struct A*));是不是看起来有点别扭?解释解释?首先malloc函数申请一块sizeof(struct A*)这么大的内存,然后将返回类型强制转换为struct A型的指针赋值给p。那么sizeof(struct A*)是多大呢?熟悉指针的人都知道一般是4个字节,实在不知道的话,进入调试状态在watch窗口输入sizeof(p),因为p为struct A*,其大小即struct A*大小。
问题已经非常明显了,我们要动态开辟一个struct A型的p,那么开创的空间肯定要和struct A一样大的,4字节够了吗?原来是多了一个*。更正以后运行,正确无误了。
问题是比较简单的,也是非常容易解决的。但是,如果你忘记了free(不会报任何错误),而且你有将动态分配的p进行了很多其他的操作的时候,或者是在其他地方也动态开辟了内存的话。那么你会发现怎么这些数据都非常的奇怪,居然是凭空产生的,非常难以理解。明明是整个的思路,逻辑,语法都没错却有这样奇怪的结果。再回到前面的问题,我们只给p分配了4个字节,那么他是怎么访问结构体里面的100个int型的数据呢?这就不的不提起数组越界了。C是不对越界进行检查的,所以p中就如上面所提到的正确访问,正确赋值,正确输出。但是它访问的并不是它所拥有的空间,也就是其他变量的,如果其他变量进行其他操作的话,它的值也就变了。至于怎么变就不知道了。
至于笔者所遇见的就更为奇特了。其他的地方都是没有错误的,甚至调试的时候也是没有错误的,输出结果完全正确,只是一旦点了VC上面的执行的时候,输出结果出现了几个非常奇怪的数。之后在command line下运行也是没有问题的。
非常非常的奇怪。
总而言之,malloc还是不用比较好,尽管我们只给p分配了4个字节但是它给我们的反馈是:
其实从这也能够看出一些端倪,就不在细说了。建议是使用new代替malloc,alloc等。
不要忘记回收内存。
原作于2012年9月15日