程序在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
相关产品推荐
相关产品推荐

