C语言动态分配字符串数组实现学生成绩统计代码故障求助
C语言动态数组存储学生信息与平均分计算问题排查与修正
原代码核心错误分析
- 字符串数组分配错误:要存储
no个学生姓名(每个是字符串),需要char**类型的二维指针,而非char*。原代码char* g = (char*)malloc(no* sizeof(char));仅分配了no个字符的空间,无法存储多个字符串。 - 逗号表达式滥用:
while (n != no , n++)这类写法中,逗号表达式的结果是右侧值,导致循环条件失效,实际会变成无限循环(直到n溢出)。正确的循环条件应使用n < no,或改用for循环更直观。 - 姓名读取错误:
- 单个姓名内存分配错误:
g[n] = malloc(no* sizeof(char));按学生数量分配内存完全不合理,应按姓名最大长度(比如256字节)分配。 - 读取格式错误:
scanf_s("%c", &g[n]);用%c只能读取单个字符,无法读取完整姓名,且未处理输入缓冲区的换行符,会导致读取异常。
- 单个姓名内存分配错误:
- 成绩数组逻辑混乱:
- 类型不匹配:
char* w = (double*)malloc(p * sizeof(double));将double*强制转为char*,后续访问会触发类型错误。 - 无意义的重复分配:循环内
w[n] = malloc(p * sizeof(char));完全错误,w是成绩数组(double*),不需要给每个元素再分配内存,且n是学生索引,此时访问w[n]会触发越界。
- 类型不匹配:
- 循环变量未重置:
i、op等循环变量在处理新学生时未重置为0,导致后续循环无法执行。 - 平均分计算与输出错误:
- 计算逻辑错误:
b = w[op] / n;没有累加成绩,直接用单个成绩除以学生数量,完全不符合平均分计算逻辑。 - 输出错误:
printf(" e %f\n", & b);传递了b的地址而非值,会输出错误内容。
- 计算逻辑错误:
修正后的完整代码
#include<stdio.h> #include <stdlib.h> #include <string.h> #define NAME_MAX_LEN 256 // 定义姓名最大长度 typedef struct { char* name; double* grades; int grade_count; double average; } Student; // 用结构体统一存储学生信息,逻辑更清晰 int main() { int student_count = 0; printf("请输入学生数量:\n"); scanf_s("%d", &student_count); // 分配学生结构体数组 Student* students = malloc(student_count * sizeof(Student)); if (students == NULL) { printf("内存分配失败!\n"); return 1; } // 逐个输入学生信息 for (int i = 0; i < student_count; i++) { // 分配姓名内存 students[i].name = malloc(NAME_MAX_LEN * sizeof(char)); if (students[i].name == NULL) { printf("姓名内存分配失败!\n"); return 1; } printf("请输入第%d个学生的姓名:", i+1); // 清除scanf_s留下的换行符,避免读取空字符串 getchar(); fgets(students[i].name, NAME_MAX_LEN, stdin); // 去掉fgets读取的换行符 students[i].name[strcspn(students[i].name, "\n")] = '\0'; // 输入该学生的科目数量 printf("请输入该学生的成绩数量:\n"); scanf_s("%d", &students[i].grade_count); // 分配成绩数组内存 students[i].grades = malloc(students[i].grade_count * sizeof(double)); if (students[i].grades == NULL) { printf("成绩内存分配失败!\n"); return 1; } // 输入成绩并计算平均分 double total = 0.0; for (int j = 0; j < students[i].grade_count; j++) { printf("请输入第%d门成绩:", j+1); scanf_s("%lf", &students[i].grades[j]); total += students[i].grades[j]; } students[i].average = total / students[i].grade_count; } // 输出所有学生的平均分 printf("\n===== 学生平均分结果 =====\n"); for (int i = 0; i < student_count; i++) { printf("学生%s的平均分:%.2lf\n", students[i].name, students[i].average); } // 释放内存,避免泄漏 for (int i = 0; i < student_count; i++) { free(students[i].name); free(students[i].grades); } free(students); return 0; }
关键知识点说明
- 动态字符串数组:存储多个字符串需要
char**(或结构体中的char*数组),每个元素单独分配内存,确保能存储完整字符串。 - 输入处理:使用
fgets读取姓名可以避免scanf跳过空格的问题,同时要处理输入缓冲区的换行符;读取double类型浮点数时,对应格式符是%lf。 - 结构体的使用:用结构体封装学生的姓名、成绩数组、成绩数量和平均分,代码逻辑更清晰,便于维护。
- 内存管理:所有动态分配的内存(姓名、成绩数组、学生数组)都要记得释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者hahahaY
相关产品推荐
相关产品推荐

