首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言結構體數組實戰:學生成績管理系統完整版(輸入、統計、輸出)

     編輯:關於C語言

問題描述

5 名學生,信息含:學號、姓名、三門課成績(C++、高數、英語)。要求:

  1. 鍵盤輸入 5 學生信息;
  2. 計算總分、平均分並存入結構體;
  3. 輸出學號、姓名、總分、平均分。

核心考點:結構體數組、字符串輸入、模塊化函數設計、浮點數精度。

標準實現


#include <stdio.h>

struct Student {
    char num[12];      // 學號
    char name[15];     // 姓名
    float cpp;         // C++
    float math;        // 高數
    float english;     // 英語
    float sum;         // 總分
    float avg;         // 平均分
};

void calculate(struct Student stu[], int n);

int main() {
    struct Student students[5];
    int i;

    printf("請輸入5位學生信息 (學號 姓名 英語 高數 C++):\n");
    for (i = 0; i < 5; i++) {
        // 注意:%s 讀取到空白符,姓名含空格需用 fgets 或掃描集
        scanf("%11s %14s %f %f %f",
              students[i].num,
              students[i].name,
              &students[i].english,
              &students[i].math,
              &students[i].cpp);
    }

    calculate(students, 5);
    return 0;
}

void calculate(struct Student stu[], int n) {
    for (int i = 0; i < n; i++) {
        stu[i].sum = stu[i].math + stu[i].english + stu[i].cpp;
        stu[i].avg = stu[i].sum / 3.0f;
    }

    printf("\n%-12s %-15s %8s %8s\n", "學號", "姓名", "總分", "平均分");
    for (int i = 0; i < n; i++) {
        printf("%-12s %-15s %8.2f %8.2f\n",
               stu[i].num, stu[i].name, stu[i].sum, stu[i].avg);
    }
}

關鍵技術點深度解析

1. 字符串輸入陷阱與對策

方法代碼優點缺點
scanf("%s")scanf("%14s", name)簡單遇空格截斷,無法讀「張 三」
scanf("%[^\n]")scanf(" %14[^\n]", name)讀整行含空格需處理殘留換行符
fgetsfgets(name, 15, stdin)安全、標準含換行符需手動去除

建議:教學簡化用 %s,實戰必用 fgets + 去換行。

2. 緩衝區溢出防護:寬度限制


// 數組大小 12 → 最大讀 11 字符 + \0
scanf("%11s", stu[i].num);   // %11s 限制讀取寬度
// 名稱同理 %14s

原代碼無寬度限制,輸入超長字符串會導致緩衝區溢出,嚴重安全漏洞。

3. 結構體設計原則

  • 數據局部性:相關數據聚合,利於緩存;
  • 擴展性:易添加排名、GPA、地址等字段;
  • 語義清晰:字段名見名知意(sum 優於 score)。

4. 浮點數輸出格式化


printf("%.2f", avg);  // 保留兩位小數,符合成績單習慣
// 原代碼 %f 輸出 6 位小數(如 85.333333),閱讀性差

進階擴展:動態內存分配版(支持任意學生數)


struct Student *allocate_students(int n) {
    struct Student *stu = malloc(n * sizeof(struct Student));
    if (!stu) { perror("內存不足"); exit(1); }
    return stu;
}

void free_students(struct Student *stu) { free(stu); }

// 主程序
int n;
printf("學生人數: "); scanf("%d", &n);
struct Student *students = allocate_students(n);
// ... 輸入計算輸出 ...
free_students(students);

工程化增強:輸入驗證與錯誤恢復


bool read_student(struct Student *s) {
    printf("學號 姓名 英語 高數 C++: ");
    // 讀整行再解析,避免 scanf 失敗留下垃圾
    char line[256];
    if (!fgets(line, sizeof(line), stdin)) return false;

    // 解析:學號 姓名 三門分數
    // 假設姓名無空格,簡化用 sscanf
    if (sscanf(line, "%11s %14s %f %f %f",
               s->num, s->name, &s->english, &s->math, &s->cpp) != 5) {
        printf("格式錯誤,請重新輸入\n");
        return false;
    }
    // 分數範圍檢查
    if (s->english < 0 || s->english > 100 ||
        s->math < 0 || s->math > 100 ||
        s->cpp < 0 || s->cpp > 100) {
        printf("分數必須在 0-100 之間\n");
        return false;
    }
    return true;
}

總結

學生成績管理是結構體數組、字符串處理、模塊化設計、輸入驗證的綜合實戰。關鍵收穫:

  • 結構體數組實現「數據與操作」初步封裝;
  • scanf 寬度限制 (%11s) 是防溢出底線;
  • 浮點輸出 %.2f 符合業務習慣;
  • 動態分配 malloc 突破固定規模限制;
  • 工程級輸入採用 fgets + sscanf 組合,健壯性遠超 scanf。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved