结构体中使用动态数组的C代码问题:realloc触发后程序异常
问题分析与修复
你的代码主要有几个致命问题导致触发扩容时程序崩溃,以下是具体错误点和修复方案:
1. 扩容后主函数的指针未更新
addCar函数中,car_list是按值传递的局部变量,realloc返回的新内存地址仅在函数内部有效,主函数里的原始指针仍然指向已经被释放的旧内存块。后续通过旧指针访问内存会直接触发未定义行为(程序崩溃)。
修复方案:将addCar的参数改为指针的指针,让函数能直接修改主函数中的指针:
int addCar(struct _Car_List_** car_list, int id, char* name) { struct _Car_* car = createCar(id, name); if (!car) return -1; // 新增检查car是否创建成功 struct _Car_List_* list = *car_list; if (list->number_of_cars_ == list->max_number_of_cars_) { list->max_number_of_cars_ += SIZE; // 先保存realloc结果,避免原指针丢失 struct _Car_List_* new_list = realloc(list, sizeof(struct _Car_List_) + list->max_number_of_cars_ * sizeof(struct _Car_*)); if (!new_list) { free(car); // 避免内存泄漏 return -1; } *car_list = new_list; // 更新主函数的指针 list = new_list; } list->cars_[list->number_of_cars_] = car; list->number_of_cars_++; return 0; }
调用时需要传递指针的地址:
addCar(&car_list, 1, "A"); // ... 其他addCar调用同理
2. realloc的错误检查逻辑完全错误
原代码中用if (car_list->cars_ == NULL)判断扩容是否失败,这是错误的:
- 如果
realloc失败,会返回NULL,此时car_list已经是NULL,访问car_list->cars_会直接触发空指针解引用崩溃。 - 正确的做法是直接判断
realloc的返回值是否为NULL。
3. 打印函数的循环越界
printCars函数中,循环逻辑错误:先取元素再自增i,当i等于number_of_cars_时,仍然会访问car_list->cars_[i],这时候已经超出数组的有效范围,会导致非法内存访问。
修复方案:调整循环逻辑,先检查i的范围再取元素:
void printCars(struct _Car_List_* car_list) { for (int i = 0; i < car_list->number_of_cars_; i++) { struct _Car_* car = car_list->cars_[i]; printf("- %s [%d]\n", car->name_, car->id_); } }
其他潜在问题(建议修复)
createCar中直接赋值字符串指针:如果传入的是动态分配的字符串,后续释放时容易出现问题。建议改为字符串拷贝(需要包含<string.h>):
struct _Car_* createCar(int id, char* name) { struct _Car_* car = malloc(sizeof(struct _Car_)); if (!car) return NULL; car->name_ = strdup(name); if (!car->name_) { free(car); return NULL; } car->id_ = id; return car; }
- 缺少内存释放逻辑:程序结束时未释放分配的内存,会造成内存泄漏。建议添加清理函数:
void freeCarList(struct _Car_List_* car_list) { if (!car_list) return; for (int i = 0; i < car_list->number_of_cars_; i++) { free(car_list->cars_[i]->name_); // 如果用了strdup则需要释放 free(car_list->cars_[i]); } free(car_list); }
在main函数末尾调用:freeCarList(car_list);
完整修正代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define SIZE 3 struct _Car_ { char* name_; int id_; }; struct _Car_List_ { int number_of_cars_; int max_number_of_cars_; struct _Car_* cars_[]; }; struct _Car_* createCar(int id, char* name) { struct _Car_* car = malloc(sizeof(struct _Car_)); if (!car) return NULL; car->name_ = strdup(name); if (!car->name_) { free(car); return NULL; } car->id_ = id; return car; } int addCar(struct _Car_List_** car_list, int id, char* name) { struct _Car_* car = createCar(id, name); if (!car) return -1; struct _Car_List_* list = *car_list; if (list->number_of_cars_ == list->max_number_of_cars_) { list->max_number_of_cars_ += SIZE; struct _Car_List_* new_list = realloc(list, sizeof(struct _Car_List_) + list->max_number_of_cars_ * sizeof(struct _Car_*)); if (!new_list) { free(car->name_); free(car); return -1; } *car_list = new_list; list = new_list; } list->cars_[list->number_of_cars_] = car; list->number_of_cars_++; return 0; } void printCars(struct _Car_List_* car_list) { for (int i = 0; i < car_list->number_of_cars_; i++) { struct _Car_* car = car_list->cars_[i]; printf("- %s [%d]\n", car->name_, car->id_); } } void freeCarList(struct _Car_List_* car_list) { if (!car_list) return; for (int i = 0; i < car_list->number_of_cars_; i++) { free(car_list->cars_[i]->name_); free(car_list->cars_[i]); } free(car_list); } int main() { struct _Car_List_* car_list = malloc(sizeof(struct _Car_List_) + SIZE * sizeof(struct _Car_*)); car_list->number_of_cars_ = 0; car_list->max_number_of_cars_ = SIZE; printf("Num of cars = %d\n", car_list->number_of_cars_); addCar(&car_list, 1, "A"); printf("Num of cars = %d\n", car_list->number_of_cars_); addCar(&car_list, 2, "B"); printf("Num of cars = %d\n", car_list->number_of_cars_); addCar(&car_list, 3, "C"); printf("Num of cars = %d\n", car_list->number_of_cars_); addCar(&car_list, 4, "D"); printf("Num of cars = %d\n", car_list->number_of_cars_); printCars(car_list); freeCarList(car_list); return 0; }
内容的提问来源于stack exchange,提问作者3nondatur
相关产品推荐
相关产品推荐

