Malloc调用在第二次执行时崩溃的原因排查求助
程序循环调用时第二次崩溃的原因分析
问题背景
程序需返回指向内存中学生对象的指针数组,首次运行正常,但在循环3次调用该操作的场景中,第二次运行时在malloc行崩溃,编译器未给出报错信息。
相关代码
目标函数getMyStudentBySize
Student **getMyStudentBySize(Student *allStudent, int wantSize, int maxsize, Teacher *pteacher) { int counter = 0; Student **myStudent = (Student **)malloc(1 * sizeof(Student *)); for (int i = 0; i < MAX_TOTAL_STUDENT; i++) { for (int h = 0; h < NUMBER_OF_CLASSES; h++) { if (allStudent[i].myClassRoom) { if (strcmp(allStudent[i].myTeachers[h]->name, (char *)pteacher->name) == 0) { myStudent[counter++] = &allStudent[i]; break; } } else break; } } return myStudent; }
调用函数assignTeacher
void assignTeacher(Teacher **teacherArray, ClassRoom **allClassRooms, Student *allStudents) { int mySize = helperAssignTeacher(allStudents, *teacherArray, NULL); Student **myStudentFor = getMyStudentBySize(allStudents, mySize, allClassRooms[chooseClassRoom - 1]->maxSize, ((*teacherArray) + (chooseTeacher - 1))); printAllStudent(myStudentFor, allClassRooms[chooseClassRoom - 1]->maxSize); }
崩溃发生在第二次执行getMyStudentBySize时的这行代码:
Student **myStudent = (Student **)malloc(1 * sizeof(Student *));
崩溃原因分析
- 堆内存损坏:
getMyStudentBySize中仅分配了1个Student*的内存空间,但后续循环中counter会随着找到符合条件的学生而递增,当学生数量超过1时,myStudent[counter++]会写入超出分配范围的内存,直接破坏堆结构。第一次调用可能因堆损坏未被立即检测到而正常运行,但堆已处于异常状态,第二次调用malloc时,堆管理器检测到损坏就会触发崩溃。 - 参数未合理利用:函数参数
wantSize和maxsize完全未被使用,这两个参数本应用来提前计算并分配足够的内存空间,却被忽略,导致内存分配不足。 - 空指针解引用风险:代码中直接访问
allStudent[i].myTeachers[h]->name,未检查allStudent[i].myTeachers[h]是否为空,若该指针为空会触发未定义行为,可能间接破坏内存。另外,pteacher->name被强制转换为char*,如果原类型并非char*,会导致字符串比较时的内存访问错误。 - 内存泄漏:
getMyStudentBySize返回的指针数组在assignTeacher中使用后未被free,多次调用会累积内存泄漏,长期运行可能耗尽内存,也可能间接影响堆的稳定性。
修复方案
- 按需分配足够内存:先统计符合条件的学生数量,再分配对应大小的内存,避免越界:
Student **getMyStudentBySize(Student *allStudent, int wantSize, int maxsize, Teacher *pteacher) { int counter = 0; // 第一步:统计符合条件的学生数量 for (int i = 0; i < MAX_TOTAL_STUDENT; i++) { if (!allStudent[i].myClassRoom) { break; } for (int h = 0; h < NUMBER_OF_CLASSES; h++) { if (allStudent[i].myTeachers[h] && strcmp(allStudent[i].myTeachers[h]->name, pteacher->name) == 0) { counter++; break; } } } // 分配对应数量的指针内存 Student **myStudent = (Student **)malloc(counter * sizeof(Student *)); if (!myStudent) { // 处理内存分配失败的情况 return NULL; } // 第二步:填充学生指针 counter = 0; for (int i = 0; i < MAX_TOTAL_STUDENT; i++) { if (!allStudent[i].myClassRoom) { break; } for (int h = 0; h < NUMBER_OF_CLASSES; h++) { if (allStudent[i].myTeachers[h] && strcmp(allStudent[i].myTeachers[h]->name, pteacher->name) == 0) { myStudent[counter++] = &allStudent[i]; break; } } } return myStudent; }
- 添加空指针检查:访问指针成员前先判断指针是否为空,避免未定义行为。
- 释放内存:在
assignTeacher中调用printAllStudent后,添加内存释放代码:
printAllStudent(myStudentFor, allClassRooms[chooseClassRoom - 1]->maxSize); free(myStudentFor); // 释放分配的指针数组
- 移除不必要的强制转换:确保
pteacher->name本身就是char*类型,若类型不匹配需修正定义,而非强制转换。
内容的提问来源于stack exchange,提问作者Bubi
相关产品推荐
相关产品推荐

