C语言中,malloc 函数和 free 函数是在系统的堆上分配空间。
使用 malloc 时,程序会向系统索要一块内存空间,用完了之后使用 free 函数释放掉这块内存空间。
使用即踩坑!
下面是我编写的代码,目的是想生成一个链表然后再遍历一遍,但是却出了问题,代码如下:
#include <iostream>
#include <cstdlib>
using namespace std;
struct TNode{
int id;
struct TNode * father;
struct TNode * child;
};
int key = 1;
void build (struct TNode * father)
{
cout << father->id << endl;
struct TNode * temp = (struct TNode *)malloc(sizeof(TNode));
temp->id = key++;
father->child = temp;
temp->father = father;
if ( key >= 100 ){
temp->child=NULL;
return;
}
build(temp);
free(temp);
return;
}
int main(void)
{
struct TNode * root = (struct TNode *)malloc(sizeof(TNode));
root->id = key++;
build(root);
cout << "=============================================" << endl;
while ( root!=NULL ){
cout << root->id << endl;
root = root->child;
}
free(root);
return 0;
}
输出结果
在遍历输出各节点的 id 时,中间出现了错误,输出了一块看着像内存地址的数字。
其实是因为在 build() 函数的倒数第二行使用了 free ,才导致了这个问题。
正确代码
void build (struct TNode * father)
{
cout << father->id << endl;
struct TNode * temp = (struct TNode *)malloc(sizeof(TNode));
temp->id = ++key;
father->child = temp;
temp->father = father;
if ( key >= 100 ){
temp->child=NULL;
return;
}
build(temp);
//free(temp);
return;
}
输出结果
原因分析
free() 释放掉的是指针指向的内存,而指针只是一个变量,只有程序结束时才被销毁。
在第一个程序中,调用一次 build() 函数意味着生成一个链表节点,这是指针 temp 是指向这个链表节点所在的内存空间的,且这个内存空间目前是被使用的,系统或者其他程序不能对这块空间进行操作,但是 free() 掉了之后,这块空间就是可以被其他程序使用的了,所以才导致了如上输出时结果错误的情况。
内存空间被 free() 之后,指针变量还是存在的,仍然指向这块空间,这不过这时候这块内存空间是未定义的,因此在遍历输出的时候,中间一小段出现问题意味着这段内存空间又被其他程序所使用并修改,而输出仍然正常的意味着该内存空间还没有被其他程序所使用,即 free() 后等待垃圾回收,未必就立即被其他内容覆盖。
注
在程序结束时,使用循环将链表空间一个一个 free 掉,释放内存后要把指针指向NULL,防止指针在后面不小心又被引用了。
int main(void)
{
struct TNode * root = (struct TNode *)malloc(sizeof(TNode));
root->id = key;
build(root);
cout << "=============================================" << endl;
while ( root->child!=NULL ){
cout << root->id << endl;
struct TNode * p = root;
root = root->child;
free(p);
p = NULL; // 其实这个操作也没有必要,因为后面程序不会再使用到这个指针了
}
return 0;
}