C语言中数组内链表结构的内存释放与段错误排查
问题根源分析
你的段错误是因为错误地尝试释放并非由malloc分配的内存地址:
crea_lista函数中用malloc分配了inmap结构体,但返回的是结构体的副本(值传递),导致原malloc的指针丢失,内存泄漏。grafo的in是inmap类型的数组指针,数组中的每个inmap元素是直接存储在数组内存块中的,并非单独malloc分配的,所以&g.in[i]不是malloc返回的合法指针,调用free会触发段错误。
正确的内存释放方案
根据你的代码结构,有两种修正路径:
路径1:保持in为inmap数组(无需单独释放每个inmap)
第一步:修正crea_lista函数
既然数组中直接存储inmap结构体,就不需要为单个inmapmalloc,改为返回初始化好的结构体:
inmap crea_lista() { inmap lista; lista.head = NULL; return lista; }
第二步:正确释放整个图的内存
释放顺序是:先释放每个inmap对应的链表节点,再释放数组本身,最后释放其他资源:
void dealloca_grafo(grafo *g) { // 释放每个inmap的链表节点 for (int i = 0; i < g->N; i++) { dealloca_lista(&g->in[i]); } // 释放in数组 free(g->in); // 释放out数组 free(g->out); // 重置图的参数(可选) g->N = 0; g->in = NULL; g->out = NULL; }
路径2:改为in为inmap指针数组(每个inmap单独malloc)
如果需要每个inmap都在堆上独立分配,需调整结构体定义和创建逻辑:
第一步:修改grafo结构体定义
typedef struct { int N; // 节点数量 int *out; // 出度数组 inmap **in; // 指向inmap指针数组的指针 } grafo;
第二步:修正crea_lista函数,返回指针
inmap* crea_lista() { inmap *nuova_lista = (inmap*)malloc(sizeof(inmap)); if (nuova_lista != NULL) { nuova_lista->head = NULL; } return nuova_lista; }
第三步:创建图时初始化in数组
// 示例:创建一个含N个节点的图 grafo crea_grafo(int N) { grafo g; g.N = N; g.out = malloc(N * sizeof(int)); g.in = malloc(N * sizeof(inmap*)); for (int i = 0; i < N; i++) { g.in[i] = crea_lista(); g.out[i] = 0; // 初始化出度为0 } return g; }
第四步:释放图的内存
void dealloca_grafo(grafo *g) { // 释放每个inmap的链表节点和inmap本身 for (int i = 0; i < g->N; i++) { dealloca_lista(g->in[i]); free(g->in[i]); } // 释放指针数组和出度数组 free(g->in); free(g->out); // 重置参数 g->N = 0; g->in = NULL; g->out = NULL; }
关键注意事项
- 内存释放必须遵循谁分配谁释放的原则,只有
malloc/calloc/realloc返回的指针才能用free释放。 - 结构体值传递会导致原堆内存指针丢失,引发泄漏,需根据实际需求选择返回结构体还是指针。
内容的提问来源于stack exchange,提问作者Samuele Bertucci
相关产品推荐
相关产品推荐

