C语言链表实现学生数据库重复调用函数触发段错误求助
问题分析与修复方案
核心问题根源
空链表未处理+初始判断逻辑错误
代码开头的if (current_study == NULL || current_study == NULL)是低级笔误,重复判断了同一个变量。更致命的是:当student_head或study_head为空链表时,直接访问current_student->next_student或current_study->next_study会触发空指针段错误。你首次调用正常,说明调用前链表头已被初始化,但第二次调用时,链表遍历或内存分配环节存在漏洞。未检查
malloc返回值
每次分配内存后没有判断是否成功,若内存不足导致malloc返回NULL,后续访问节点成员会直接崩溃。野指针隐患
新分配的节点next_student/next_study未初始化,可能成为野指针,导致后续遍历出错。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> // 结构体定义保持不变 typedef struct student{ int pernum; char name[100]; int is_male; int age; char email[100]; struct student *next_student; }student; typedef struct study{ int pernum; int math; int english; int chemistry; int biology; int history; struct study *next_study; }study; // 全局变量保持不变 int num_of_stud = 0; int num_of_female = 0; int num_of_male = 0; student *current_student; study *current_study; student *student_head = NULL; study *study_head = NULL; int add_student(void){ student *new_student; study *new_study; // 处理student链表:空链表直接创建头节点,否则遍历到末尾 if (student_head == NULL) { new_student = (student*)malloc(sizeof(student)); if (!new_student) { printf("内存分配失败:学生节点\n"); return 1; } student_head = new_student; current_student = new_student; } else { current_student = student_head; while(current_student->next_student != NULL){ current_student = current_student->next_student; } new_student = (student*)malloc(sizeof(student)); if (!new_student) { printf("内存分配失败:学生节点\n"); return 1; } current_student->next_student = new_student; current_student = new_student; } current_student->next_student = NULL; // 初始化next指针,避免野指针 // 输入学生信息 printf("输入学号:"); scanf("%d", ¤t_student->pernum); printf("输入姓名:"); scanf("%s", current_student->name); printf("性别(1=男,0=女):"); scanf("%d", ¤t_student->is_male); current_student->is_male == 0 ? num_of_female++ : num_of_male++; printf("输入年龄:"); scanf("%d", ¤t_student->age); printf("输入邮箱:"); scanf("%s", current_student->email); // 处理study链表:逻辑同student链表 if (study_head == NULL) { new_study = (study*)malloc(sizeof(study)); if (!new_study) { printf("内存分配失败:学习信息节点\n"); // 回滚已分配的学生节点,避免内存泄漏 if (student_head == current_student) { free(current_student); student_head = NULL; } else { student *temp = student_head; while(temp->next_student != current_student) temp = temp->next_student; temp->next_student = NULL; free(current_student); } return 1; } study_head = new_study; current_study = new_study; } else { current_study = study_head; while(current_study->next_study != NULL){ current_study = current_study->next_study; } new_study = (study*)malloc(sizeof(study)); if (!new_study) { printf("内存分配失败:学习信息节点\n"); // 回滚学生节点 student *temp = student_head; while(temp->next_student != current_student) temp = temp->next_student; temp->next_student = NULL; free(current_student); return 1; } current_study->next_study = new_study; current_study = new_study; } current_study->next_study = NULL; // 初始化next指针 current_study->pernum = current_student->pernum; // 输入学习信息 printf("是否学数学(1=是,0=否):"); scanf("%d", ¤t_study->math); printf("是否学英语(1=是,0=否):"); scanf("%d", ¤t_study->english); printf("是否学化学(1=是,0=否):"); scanf("%d", ¤t_study->chemistry); printf("是否学生物(1=是,0=否):"); scanf("%d", ¤t_study->biology); printf("是否学历史(1=是,0=否):"); scanf("%d", ¤t_study->history); num_of_stud++; return 0; }
关键修复说明
- 空链表处理:新增判断逻辑,当链表头为空时直接创建头节点,避免空指针访问。
- 内存分配校验:每次
malloc后检查返回值,失败时回滚已分配资源,防止内存泄漏。 - 野指针消除:新节点的
next指针统一初始化为NULL,避免后续遍历出错。 - 逻辑简化:添加新节点后更新
current指针指向新节点,减少重复遍历的冗余操作。
额外优化建议
- 尽量减少全局指针使用,改用局部指针+函数参数传递链表头,降低意外修改风险。
- 用
fgets替代scanf读取字符串,避免输入过长导致缓冲区溢出(比如姓名、邮箱字段)。 - 实现链表销毁函数,程序结束时释放所有节点内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者hellothere
相关产品推荐
相关产品推荐

