C语言嵌套动态结构体数组realloc扩容内存异常问题咨询
嵌套动态结构体数组实现问题修复方案
存在的核心问题
语法不兼容问题
C 语言标准不支持结构体定义时给成员设置默认初始值,你代码里的= 0、= NULL这类写法是C的特性,要么你误使用C编译器编译C代码出现了隐式兼容问题,要么就是编译器扩展带来的未知行为,而且即使编译通过,动态分配的结构体成员也不会自动执行默认初始化。同时DLITEMTYPE::NOTYPE、DLITEMACTION::EDIT这种带::作用域的写法也是C++语法,C语言枚举不存在类作用域,直接使用枚举常量名即可。
直接将realloc用法错误realloc的返回值赋值给原指针是典型错误:如果realloc申请内存失败会返回NULL,此时原指针指向的内存会直接泄漏,同时原指针变成野指针,后续访问必然触发非法内存访问。动态分配的结构体成员未初始化
你扩容DLPage_t数组后,只给新元素的index赋值了,剩下的pageItems、pageItemCount、selectedItemIndex都是内存中的垃圾值:- 后续给该页添加元素时,
pageItemCount是随机值,++后计算的内存大小完全错误 pageItems是野指针,直接传给realloc会直接触发崩溃
- 后续给该页添加元素时,
新增的
扩容DLPageItem_t元素未初始化pageItems数组后,新的DLPageItem_t元素所有成员都是垃圾值,后续访问逻辑必然出现异常。
修正后的实现代码
1. 修正结构体定义(符合C语法)
// 提前声明DLPageItem_t,供DLPage_t引用 typedef struct DLPageItem_t DLPageItem_t; typedef struct { uint8_t index; DLPageItem_t *pageItems; uint8_t pageItemCount; uint8_t selectedItemIndex; } DLPage_t; struct DLPageItem_t { uint8_t index; void *valuePtr; uint16_t tmpValue; DLItemType_t type; uint8_t row; uint8_t col; uint8_t targetPageId; DLItemAction_t action; bool selectable; bool editing; };
2. 修正DLPage_t数组扩容逻辑
// 用临时指针接收realloc返回值,避免申请失败内存泄漏 DLPage_t *tmp_page = realloc(this->_pages, (this->_pageCount + 1) * sizeof(DLPage_t)); if (tmp_page == NULL) { // 内存申请失败的错误处理逻辑,不要修改原指针和计数 return -1; } this->_pages = tmp_page; this->_pageCount++; // 新页全量初始化,避免垃圾值 DLPage_t *new_page = &this->_pages[this->_pageCount - 1]; memset(new_page, 0, sizeof(DLPage_t)); new_page->index = this->_pageCount - 1; // 其他自定义初始值可在此补充
3. 修正添加DLPageItem_t逻辑
// 先校验pageId合法性,避免越界 if (pageId >= this->_pageCount || this->_pages == NULL) { return -1; } DLPage_t *target_page = &this->_pages[pageId]; // 扩容item数组 DLPageItem_t *tmp_item = realloc(target_page->pageItems, (target_page->pageItemCount + 1) * sizeof(DLPageItem_t)); if (tmp_item == NULL) { return -1; } target_page->pageItems = tmp_item; target_page->pageItemCount++; // 新item初始化,避免垃圾值 DLPageItem_t *new_item = &target_page->pageItems[target_page->pageItemCount - 1]; memset(new_item, 0, sizeof(DLPageItem_t)); // 设置自定义初始值,注意C语言枚举直接用常量名 new_item->type = DLITEMTYPE_NOTYPE; new_item->action = DLITEMACTION_EDIT; // 其他自定义初始值可在此补充
额外注意事项
每次访问数组前都要校验下标合法性、指针非空,避免越界访问。如果你的项目实际使用C++开发,更推荐使用std::vector管理动态数组,自动处理内存分配、扩容和初始化逻辑,避免手动管理内存的各类问题。
内容的提问来源于stack exchange,提问作者azzurro
相关产品推荐
相关产品推荐

