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

程序在student_info函数执行结束时崩溃,请求技术排查与解决

排查student_info函数执行崩溃的原因与解决办法

我来帮你拆解这个函数执行时崩溃的问题,主要有几个常见的诱因,对应的解决办法也给你列出来:

崩溃的核心原因

1. 指针参数传入了无效内存(空指针/野指针/只读内存)

这是最常见的崩溃原因:

  • 如果你调用函数时,给hw1、hw2这类整数指针传了NULL,或者是未初始化的野指针,那么scanf("%d", &(*hw1))(等价于scanf("%d", hw1))会尝试往非法内存地址写数据,直接触发段错误。
  • 如果给name参数传了字符串字面量(比如student_info("Tom", ...)),因为字面量存在只读内存区域,gets_s尝试写入时会触发访问权限错误导致崩溃;要是name是未初始化的野指针,写入操作同样会访问非法内存。

2. gets_s缓冲区大小不匹配导致越界

gets_s(name, 20)要求传入的name缓冲区至少有20字节的可写空间,如果调用时传入的缓冲区实际大小小于20,写入名字时会发生缓冲区越界,破坏栈上的其他数据(比如后面指针参数的地址),后续执行scanf时就会出现不可预测的崩溃。

3. scanf输入错误引发的未定义行为

如果用户输入的不是整数(比如输入字母代替成绩),scanf会读取失败,此时对应的指针指向的内存值不确定,甚至可能因为输入流混乱,后续操作触发非法内存访问。


对应的解决办法

1. 确保所有指针参数指向有效可写内存

  • 对于name:要么声明栈上数组(比如char name[20];),要么用malloc分配内存(char *name = malloc(20);,记得用完后free),绝对不能传只读的字符串字面量或未初始化指针。
  • 对于hw1、ex1这类整数指针:调用时直接传入栈上变量的地址,比如:
    int hw1, hw2, hw3, ex1, ex2;
    student_info(name, &hw1, &hw2, &hw3, &ex1, &ex2);
    
    这样指针就指向了有效的栈内存,写入操作是安全的。

2. 修复gets_s的缓冲区大小问题

最好把缓冲区大小作为参数传入函数,避免硬编码20的限制,让函数更健壮:

void student_info(char *name, size_t name_buf_size, int *hw1, int *hw2, int *hw3, int *ex1, int *ex2) { 
    printf("Please enter the student's name:\n"); 
    gets_s(name, name_buf_size); 
    printf("\nPlease enter the student's homework grades:\n"); 
    scanf("%d %d %d", hw1, hw2, hw3); // 这里&(*hw1)等价于hw1,直接写hw1更简洁
    printf("\nPlease enter the student's exam scores:\n"); 
    scanf("%d %d", ex1, ex2); 
}

调用时传入实际的缓冲区大小,比如student_info(name, sizeof(name), ...)(如果name是栈数组)。

3. 处理scanf的输入错误,避免未定义行为

每次调用scanf后检查返回值,确保读取到了预期数量的输入,同时清空输入流的残留字符:

// 读取作业成绩时的检查
if (scanf("%d %d %d", hw1, hw2, hw3) != 3) {
    printf("Invalid homework grades input!\n");
    // 清空输入缓冲区直到换行,避免影响后续输入
    while (getchar() != '\n');
    return;
}

// 读取考试成绩同理
if (scanf("%d %d", ex1, ex2) != 2) {
    printf("Invalid exam scores input!\n");
    while (getchar() != '\n');
    return;
}

4. 额外优化:替换gets_s为跨平台的fgets

gets_s是微软特定的安全函数,跨平台兼容性差,换成fgets更通用,同时手动去掉读取到的换行符:

fgets(name, name_buf_size, stdin);
// 用strcspn找到换行符的位置,替换为结束符
name[strcspn(name, "\n")] = '\0';

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:04:08