C语言中释放数组时出现问题的原因及排查
你的C语言数组操作程序的问题分析与修复方案
代码中的核心问题
- 结构体语法错误:
struct table_t里的int size末尾缺少分号,会直接导致编译失败。 table_new未返回结构体:函数声明返回table_t,但仅分配内存却没返回创建好的结构体,主函数调用后t.data始终是未初始化的野指针,后续所有内存操作都是非法访问。- 传值调用导致修改无效:
table_append、table_delete等函数直接传结构体值,内部修改的是副本,完全不影响主函数里的原结构体。比如table_append赋值的是副本的数组,原结构体的data还是野指针;table_delete释放的也是副本的内存,原结构体的data依然是野指针,最终触发valgrind异常。 scanf格式符错误:"%d "里的多余空格会让scanf读取整数后继续等待空白字符,导致输入流程异常。- 释放内存后非法访问:
table_delete释放内存后,主函数仍调用table_printf,此时访问的是已释放的野指针,属于未定义行为。 - 函数返回值缺失:
table_append声明返回int、table_delete声明返回table_t,但都没有返回值,会引发编译警告甚至运行时异常。
修正后的完整代码
#include <stdlib.h> #include <stdio.h> // 补充printf需要的头文件 typedef struct table_t { double* data; int size; // 补上缺失的分号 } table_t; table_t table_new(int n) { table_t t; t.size = n; t.data = malloc(sizeof(double) * n); // 添加malloc失败的容错处理 if (t.data == NULL) { t.size = 0; } return t; // 返回初始化完成的结构体 } void table_printf(const table_t *tab) { if (tab == NULL || tab->data == NULL || tab->size <= 0) { return; } for(int i = 0; i < tab->size; i++){ printf("%lf\n", tab->data[i]); } } void table_append(double val, table_t *tab) { if (tab == NULL || tab->data == NULL || tab->size <= 0) { return; } for(int i = 0; i < tab->size; i++){ tab->data[i] = val; } } void table_delete(table_t *tab) { if (tab == NULL) { return; } free(tab->data); tab->data = NULL; // 释放后置空,避免野指针 tab->size = 0; } int main() { table_t t; printf("输入数组大小:"); scanf("%d", &t.size); // 去掉格式符后的多余空格 t = table_new(t.size); // 接收初始化后的结构体 table_append(5, &t); // 传结构体指针,直接修改原数据 table_printf(&t); table_delete(&t); // 释放后禁止再访问数组,注释或删除此行 // table_printf(&t); return 0; }
关键修改说明
- 所有操作结构体的函数改为传指针,避免拷贝副本且能直接修改原结构体。
table_new补全结构体返回逻辑,同时初始化size字段。- 添加参数合法性检查,避免空指针、非法大小的内存访问。
- 释放内存后置空指针并重置
size,彻底杜绝野指针问题。 - 移除释放内存后的非法打印操作。
内容的提问来源于stack exchange,提问作者Marouane Sharry
相关产品推荐
相关产品推荐

