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

C语言学生结构体总分计算与冒泡排序实现优化及问题排查

C语言学生成绩管理作业代码问题排查与优化

我是C语言初学者,熬夜写完了课程作业,想确认现有实现有没有错误,以及是否存在更高效的写法。

本次作业定义的学生结构体如下:

typedef struct student {
    int id;
    int prob_1;
    int prob_2;
    int prob_3;
    int total_score;
    char grade;
}Student

我通过typedef将结构体类型重命名为Student,实现的两个功能函数如下:

void cal_total_score(Student* s) {
    /*
    问题(A):
    实现函数"cal_total_score"。
    - 每个学生的total_score为prob_1、prob_2、prob_3三项分数之和
    - 函数外的代码不得修改
    */
    int i;
    for (i = 0; i < NUMSTUDENT; i++) {
        s[i].total_score = s[i].prob_1 + s[i].prob_2 + s[i].prob_3;
    }
}

void student_bb_sort(Student* s) {
    /*
    问题(B):
    实现函数"student_bb_sort"。
    - 学生数组"s"需按照total_score字段排序
    - 必须使用冒泡排序算法
    - 函数外的代码不得修改
    */
    Student tmp;
    int i, j;

    for (i = 0; i < NUMSTUDENT - 1; i++) {
        for (j = 0; j < NUMSTUDENT - 1 - i; j++) {
            if (s[j].total_score > s[j + 1].total_score) {
                tmp = s[j];
                s[j] = s[j + 1];
                s[j + 1] = tmp;
            }
        }
    }
}

最初因篇幅限制省略了main函数,现将题目提供的main函数补充如下供参考:

typedef struct student {
    int id;
    int prob_1;
    int prob_2;
    int prob_3;
    int total_score;
    char grade;
}Student;

void cal_total_score(Student* s);
void student_bb_sort(Student* s);

int main() {
    Student s[NUMSTUDENT];
    int i;

    for (i = 0; i < NUMSTUDENT; i++) {
        s[i].id = i;
        s[i].prob_1 = rand() % 30 + 1;
        s[i].prob_2 = rand() % 30 + 1;
        s[i].prob_3 = rand() % 40 + 1;
        printf("Student %d\nP1: %d\tP2: %d\tP3: %d\n", s[i].id, s[i].prob_1, s[i].prob_2, s[i].prob_3);
    }

    for (i = 0; i < NUMSTUDENT; i++) {
        cal_total_score(&s[i]);
        printf("Student %d\tScore: %d\n", s[i].id, s[i].total_score);
    }

    student_bb_sort(s);
    printf("\nAfter Bubble Sort\n");

    for (i = 0; i < NUMSTUDENT; i++) {
        if ((float)i < (float)NUMSTUDENT / 3) {
            s[i].grade = 'C';
        }
        else if ((float)i < (float)NUMSTUDENT / 3 * 2 && (float)i >= (float)NUMSTUDENT / 3) {
            s[i].grade = 'B';
        }
        else {
            s[i].grade = 'A';
        }
        printf("Student %d\tScore: %d\tGrade: %c\n", s[i].id, s[i].total_score, s[i].grade);
    }
}

请帮忙指出代码中存在的错误、危险写法,以及可提升效率的优化方案,谢谢。


现存问题说明

1. 直接导致编译/运行失败的硬错误

  • 结构体定义缺少分号:第一次贴出的结构体定义末尾}Student后没有分号,C语言中结构体typedef定义必须以分号结尾,属于语法错误,会直接编译失败。
  • cal_total_score函数逻辑和调用方式完全不匹配:main函数中是循环传入单个学生的指针&s[i],但当前实现直接把传入指针当成长度为NUMSTUDENT的数组首地址遍历。当i=0时传入的是数组首地址,循环计算碰巧能覆盖整个数组;但i=1时传入的是s[1]的地址,函数内部访问s[i]就会从s[1]开始往后偏移,最终访问到数组外的野内存,属于越界写入的未定义行为,轻则分数计算完全错误,重则程序直接崩溃。
  • 依赖项缺失:代码中用到的NUMSTUDENT宏没有提前定义,使用printf、rand没有引入<stdio.h>、<stdlib.h>头文件,main函数末尾缺少return 0;和闭合大括号,都会导致编译失败。

2. 效率与逻辑严谨性问题

  • 冒泡排序缺少提前终止优化:当前实现无论数组是否已经有序,都会固定跑满NUMSTUDENT-1轮遍历,做了很多无用功。如果某一轮遍历中没有发生任何交换,说明数组已经完全有序,可以直接终止排序。
  • 等级判断存在冗余与精度风险:main函数中判断B等级时重复写了(float)i >= (float)NUMSTUDENT / 3的条件,实际上进入else if分支的前提就是前面的if条件不成立,该判断完全多余;另外大量将整数转成浮点数做比较,不仅有额外的类型转换开销,还可能因为浮点数精度问题出现判断错误,用整数运算实现会更稳妥高效。
  • 随机数未设种子:main函数中直接调用rand()生成分数,没有用srand()设置随机种子,每次运行程序生成的分数序列都是完全一样的,不过这部分属于题目提供的代码,要求不能修改的话可以不用调整。

优化实现(严格遵守函数外代码不修改的要求)

修正后的cal_total_score

因为每次调用传入的是单个学生的指针,不需要循环遍历,直接操作当前传入的学生即可:

void cal_total_score(Student* s) {
    s->total_score = s->prob_1 + s->prob_2 + s->prob_3;
}

如果允许修改main函数的调用逻辑,更高效的写法是只调用一次函数,传入数组首地址,在函数内循环计算所有学生总分,减少多次函数调用的开销,但题目要求函数外代码不能改动,所以以上写法是唯一符合要求的正确实现。

优化后的student_bb_sort

保留原有的升序逻辑(分数从低到高排列,和后续C/B/A的等级评定逻辑匹配),增加交换标记实现提前终止,减少无效遍历:

void student_bb_sort(Student* s) {
    Student tmp;
    int i, j;
    int swapped; // 标记当前轮次是否发生过交换

    for (i = 0; i < NUMSTUDENT - 1; i++) {
        swapped = 0; // 每轮开始前重置标记
        for (j = 0; j < NUMSTUDENT - 1 - i; j++) {
            if (s[j].total_score > s[j + 1].total_score) {
                tmp = s[j];
                s[j] = s[j + 1];
                s[j + 1] = tmp;
                swapped = 1;
            }
        }
        if (!swapped) break; // 本轮无交换,数组已有序,直接退出
    }
}

main函数可选优化(若允许修改题目提供的代码)

去掉冗余判断和浮点数转换,用整数运算实现等级判定,效率更高也更稳妥:

// 提前计算两个等级分界点,避免循环中重复计算
int tier_c = NUMSTUDENT / 3;
int tier_b = NUMSTUDENT * 2 / 3;
for (i = 0; i < NUMSTUDENT; i++) {
    if (i < tier_c) {
        s[i].grade = 'C';
    } else if (i < tier_b) {
        s[i].grade = 'B';
    } else {
        s[i].grade = 'A';
    }
    printf("Student %d\tScore: %d\tGrade: %c\n", s[i].id, s[i].total_score, s[i].grade);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 16:31:06