You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言链表实现学生数据库重复调用函数触发段错误求助

问题分析与修复方案

核心问题根源

  1. 空链表未处理+初始判断逻辑错误
    代码开头的if (current_study == NULL || current_study == NULL)是低级笔误,重复判断了同一个变量。更致命的是:当student_head或study_head为空链表时,直接访问current_student->next_student或current_study->next_study会触发空指针段错误。你首次调用正常,说明调用前链表头已被初始化,但第二次调用时,链表遍历或内存分配环节存在漏洞。

  2. 未检查malloc返回值
    每次分配内存后没有判断是否成功,若内存不足导致malloc返回NULL,后续访问节点成员会直接崩溃。

  3. 野指针隐患
    新分配的节点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", &current_student->pernum);

    printf("输入姓名:");
    scanf("%s", current_student->name);

    printf("性别(1=男,0=女):");
    scanf("%d", &current_student->is_male);
    current_student->is_male == 0 ? num_of_female++ : num_of_male++;

    printf("输入年龄:");
    scanf("%d", &current_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", &current_study->math);

    printf("是否学英语(1=是,0=否):");
    scanf("%d", &current_study->english);

    printf("是否学化学(1=是,0=否):");
    scanf("%d", &current_study->chemistry);

    printf("是否学生物(1=是,0=否):");
    scanf("%d", &current_study->biology);

    printf("是否学历史(1=是,0=否):");
    scanf("%d", &current_study->history);

    num_of_stud++;
    return 0;
}

关键修复说明

  • 空链表处理:新增判断逻辑,当链表头为空时直接创建头节点,避免空指针访问。
  • 内存分配校验:每次malloc后检查返回值,失败时回滚已分配资源,防止内存泄漏。
  • 野指针消除:新节点的next指针统一初始化为NULL,避免后续遍历出错。
  • 逻辑简化:添加新节点后更新current指针指向新节点,减少重复遍历的冗余操作。

额外优化建议

  • 尽量减少全局指针使用,改用局部指针+函数参数传递链表头,降低意外修改风险。
  • 用fgets替代scanf读取字符串,避免输入过长导致缓冲区溢出(比如姓名、邮箱字段)。
  • 实现链表销毁函数,程序结束时释放所有节点内存,避免内存泄漏。

内容的提问来源于stack exchange,提问作者hellothere

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 15:05:20