C语言字符串与数组使用崩溃排查:scanf_s格式符问题求助
编程作业中使用字符串时程序崩溃,触发gs_report.c中的以下代码:
if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)) { __fastfail(FAST_FAIL_STACK_COOKIE_CHECK_FAILURE); }
同时存在输入异常:用%s格式符读取姓名时崩溃,用%c时循环自动执行无需用户输入。作业要求用字符串数组存储5个学生姓名、字符数组存储字母成绩、二维double数组存储4门测试分数,实现输入、平均分计算与等级展示。
代码错误分析
- 姓名输入逻辑错误:
原代码用scanf_s("%c", &names[i]);,names[i]是对应单个学生姓名的char数组,%c仅读取单个字符,且之前输入操作残留的换行符会被%c直接读取,导致后续循环跳过用户输入。使用%s时未传入缓冲区大小参数,导致scanf_s写入越界,破坏栈结构引发崩溃。 - 分数求和越界访问:
原代码中sum += scores[i][j];位于内层循环之后,此时j的值为4(循环条件j<4结束后自增到4),但scores[i]的下标范围是0-3,越界访问栈内存破坏了栈Cookie,触发崩溃。 - 冗余代码:
初始对grades数组的赋值会被后续等级判断覆盖,无实际作用可删除。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> int main() { char names[5][100], grades[5]; // 修正为5个学生的姓名数组,每个姓名最多99字符+终止符 int i, j; double scores[5][4], averages[5]; for (i = 0; i < 5; i++) { double sum = 0; printf("enter the name of student %d: ", i + 1); // 使用scanf_s读取字符串,传入缓冲区大小避免越界 scanf_s("%s", names[i], (unsigned)_countof(names[i])); // 清除输入缓冲区残留的换行符 while (getchar() != '\n'); for(j = 0; j < 4; j++) { printf("enter test score number %d: ", j + 1); scanf_s("%lf", &scores[i][j]); } // 清除分数输入后的换行符 while (getchar() != '\n'); // 在内层循环中累加分数,避免下标越界 for(j = 0; j < 4; j++) { sum += scores[i][j]; } averages[i] = sum / 4; if (averages[i] >= 90) { grades[i] = 'A'; } else if (averages[i] >= 80) { grades[i] = 'B'; } else if (averages[i] >= 70) { grades[i] = 'C'; } else if (averages[i] >= 60) { grades[i] = 'D'; } else { grades[i] = 'F'; } } printf("\n%-20s%-20s%-20s\n", "Student Name", "Average Test Score", "Letter Grade"); printf("------------------------------------------------------------\n"); for (i = 0; i < 5; i++) { printf("%-20s%-20.2lf%-20c\n", names[i], averages[i], grades[i]); } return 0; }
关键修改说明
- 修正数组维度:将
names[100][100]改为names[5][100],匹配作业要求的5个学生,减少不必要的内存占用。 - 安全读取字符串:使用
scanf_s("%s", names[i], (unsigned)_countof(names[i])),_countof自动获取缓冲区大小,避免写入越界;每次输入后清除缓冲区的换行符,防止干扰下一次输入。 - 修复求和逻辑:将分数累加操作放到内层循环中,遍历合法下标0-3,正确计算总分。
- 优化用户提示:调整提示文本的格式,让输入引导更清晰。
内容的提问来源于stack exchange,提问作者aiden
相关产品推荐
相关产品推荐

