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

线程触发SIGTRAP错误 链表学生注册程序崩溃求助

学生课程注册C程序崩溃问题排查与解决

问题描述

我编写的学生课程注册C语言程序运行时出现崩溃,调试时收到错误提示:thread 1 received signal SIGTRAP, trace/breakpoint trap。程序采用链表实现,首次注册学生功能正常,第二次注册时程序终止,退出码为3221226356。

初始代码

#include <stdio.h>
#include <stdlib.h>
typedef struct s *student;
struct s{
    long long int code;
    char *name;
    short int age;
    float pass_mark;
    bool course;
    struct s *next;
};
student enroll(student head,long long int code1, char *name1,short int age1,bool course1){
    student p,q;
    if(head==NULL){
        head=(student)malloc(sizeof(student));
        head->code=code1;
        head->name=name1;
        head->age=age1;
        head->course=course1;
        head->next=NULL;
        
    }
    else{p=head;
        q=(student)malloc(sizeof(student));
        q->code=code1;
        q->name=name1;
        q->age=age1;
        q->course=course1;
        q->next=p;
        head=q;
    }
    return(head);
}
int main(){
    int x=0,b;
    student head=NULL,q=NULL;
    long long int code1;
    char name1[50];
    short int age;
    bool course1;
    do{
        
        printf("1.register new student. \n");
        printf("0.finish program.\n");
        printf("Enter the number of the task needed: ");
        scanf("%d",&x);
        if(x==1){
            
            printf("you chose 1: \n");
            printf("Enter the student code:");
            scanf("%lli",&code1);//code of student
            getchar();
            printf("Enter the student name");
            gets(name1);//name of student
            printf("Enter student age:");
            scanf("%hi",&age);//age of student
            printf("1-Math\n");
            printf("2-computer science");
            printf("\nEnter the number of the course: ");
            scanf("%d",&b);//number of the course
            while((b!=1)&&(b!=2)){
                printf("\nchose 1 or 2: "); 
                scanf("%d",&b);
            }
            if(b==1) course1=1; //math course
            if(b==2) course1=0; //computer science course
            head=enroll(head,code1,name1,age,course1); //fill student info 
            printf("-------------------------------------
\n");
        }
}while(x!=0);
    
    return 0;
}

程序运行日志

1.register new student.
0.finish program.
Enter the number of the task needed: 1
you chose 1:
Enter the student code:231
Enter the student name Peter
Enter student age:23
1-Math
2-computer science
Enter the number of the course: 1
-------------------------------------
1.register new student.
0.finish program.
Enter the number of the task needed: 1
you chose 1:
Enter the student code:232
Enter the student name Gary
Enter student age:38
1-Math
2-computer science
Enter the number of the course: 2

--------------------------------
Process exited after 39.01 seconds with return value 3221226356
Appuyez sur une touche pour continuer...

修改后的代码(仍存在问题)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s student;
struct s{
    long long int code;
    char *name;
    short int age;
    float pass_mark;
    bool course;
    struct s *next;
};
student* enroll(student *head,long long int code1, char name1[50],short int age1,bool course1){
    student *p,*q;
        
        p=head;
        q=(student*)malloc(sizeof(student));
        q->code=code1;
        strcpy(q->name,name1);
        q->age=age1;
        q->course=course1;
        q->next=p;
        head=q;
        
    return(head);
}
int main(){
    int x=0,b;
    student *head=NULL,*q=NULL;
    long long int code1;
    char name1[50];
    short int age;
    bool course1;
    do{
        
        printf("1.register new student. \n");
        printf("0.finish program.\n");
        printf("Enter the number of the task needed: ");
        scanf("%d",&x);
        if(x==1){
            
            printf("you chose 1: \n");
            printf("Enter the student code:");
            scanf("%lli",&code1);//code of student
            getchar();
            printf("Enter the student name: ");
            fgets(name1,50,stdin);//name of student
            printf("%s",name1);
            printf("Enter student age:");
            scanf("%hi",&age);//age of student
            printf("%d",age);
            printf("1-Math\n");
            printf("2-computer science");
            printf("\nEnter the number of the course: ");
            scanf("%d",&b);//number of the course
            while((b!=1)&&(b!=2)){
                printf("\nchoose 1 or 2: "); 
                scanf("%d",&b);
            }
            if(b==1) course1=1; //math course
            if(b==2) course1=0; //computer science course
            head=enroll(head,code1,name1,age,course1); //fill student info 
            printf("%lli",head->code);
            printf("%s",head->name);
            printf("%d",head->age);
            printf("%d",head->course);
            printf("-------------------------------------
\n");
        }
}while(x!=0);
    
    return 0;
}

核心问题分析与修复

1. 链表节点内存分配错误(初始代码致命问题)

初始代码里typedef struct s *student;把student定义成了指针类型,导致malloc(sizeof(student))只分配了一个指针的大小(通常4或8字节),但实际需要的是整个struct s结构体的内存空间。这种内存不足会导致后续写入数据时溢出,第一次操作可能没触发崩溃,第二次就会踩坏内存,引发程序终止。

  • 修复:将typedef struct s *student;改为typedef struct s student;,让student代表结构体类型,指针用student*表示;分配内存时使用malloc(sizeof(student)),确保分配足够的结构体空间。

2. 字符串未分配内存直接拷贝(修改后仍存在的问题)

修改后的代码中,结构体的char *name只是一个空指针,没有为它分配内存就直接调用strcpy(q->name, name1),这属于野指针操作,会直接破坏内存,导致崩溃。

  • 修复:在拷贝名字前,先为q->name分配足够的内存:
    // 分配内存,长度为输入字符串的长度+1(存储结束符'\0')
    q->name = malloc(strlen(name1) + 1);
    // 检查内存分配是否成功(新手可以先加这个判断,避免分配失败)
    if (q->name == NULL) {
        printf("内存分配失败\n");
        exit(1);
    }
    strcpy(q->name, name1);
    
    另外,程序结束时要遍历链表,释放每个节点的name和节点本身,避免内存泄漏:
    // 在main函数结束前添加
    student *temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp->name); // 先释放名字的内存
        free(temp);       // 再释放节点
    }
    

3. gets函数的风险与fgets的正确使用

  • gets的致命问题:gets()函数完全不检查输入长度,如果用户输入的字符串超过name1的50字节限制,会直接溢出缓冲区,破坏其他内存数据,导致程序崩溃甚至被恶意利用。哪怕测试时输入正常,只要输入超长就会出问题,所以它已经被C标准彻底废弃。
  • fgets的正确用法:fgets(name1, 50, stdin)三个参数的含义:
    1. name1:存储输入字符串的数组
    2. 50:最大读取的字符数(包括结束符\0,实际最多读49个有效字符)
    3. stdin:读取的输入流(这里是键盘输入)
      注意fgets会把输入的换行符也读进数组里,如果想要去掉换行符,可以用下面的代码:
    fgets(name1, 50, stdin);
    // 找到换行符的位置,替换成结束符
    name1[strcspn(name1, "\n")] = '\0';
    
    strcspn函数会返回第一个换行符的索引,把这个位置改成\0就能去掉多余的换行。

最终修复后的完整代码示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h> // 要包含这个头文件才能用bool类型

typedef struct s student;
struct s{
    long long int code;
    char *name;
    short int age;
    float pass_mark;
    bool course;
    struct s *next;
};

student* enroll(student *head, long long int code1, const char *name1, short int age1, bool course1){
    student *q = malloc(sizeof(student));
    if (q == NULL) {
        printf("内存分配失败\n");
        exit(1);
    }
    q->code = code1;
    // 为名字分配内存并拷贝
    q->name = malloc(strlen(name1) + 1);
    if (q->name == NULL) {
        printf("内存分配失败\n");
        free(q); // 先释放节点,避免内存泄漏
        exit(1);
    }
    strcpy(q->name, name1);
    q->age = age1;
    q->course = course1;
    q->next = head;
    return q;
}

void free_students(student *head) {
    student *temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp->name);
        free(temp);
    }
}

int main(){
    int x=0,b;
    student *head=NULL;
    long long int code1;
    char name1[50];
    short int age;
    bool course1;
    
    do{
        printf("1. 注册新学生\n");
        printf("0. 退出程序\n");
        printf("请输入操作编号: ");
        scanf("%d",&x);
        getchar(); // 吃掉scanf留下的换行符
        
        if(x==1){
            printf("你选择了注册新学生:\n");
            printf("请输入学生学号: ");
            scanf("%lli",&code1);
            getchar(); // 吃掉换行符
            
            printf("请输入学生姓名: ");
            fgets(name1, 50, stdin);
            // 去掉换行符
            name1[strcspn(name1, "\n")] = '\0';
            
            printf("请输入学生年龄: ");
            scanf("%hi",&age);
            getchar(); // 吃掉换行符
            
            printf("1-数学\n");
            printf("2-计算机科学\n");
            printf("请选择课程编号: ");
            scanf("%d",&b);
            while((b!=1)&&(b!=2)){
                printf("请选择1或2: "); 
                scanf("%d",&b);
            }
            course1 = (b == 1); // 简化写法
            
            head = enroll(head, code1, name1, age, course1);
            printf("注册成功!当前头节点信息:\n");
            printf("学号: %lld\n姓名: %s\n年龄: %d\n课程: %s\n", 
                   head->code, head->name, head->age, 
                   head->course ? "数学" : "计算机科学");
            printf("-------------------------------------\n");
        }
    }while(x!=0);
    
    free_students(head); // 释放所有内存
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:29:55