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

C 語言二維數組實戰:學生成績管理系統 - 總分與平均分計算

     編輯:關於C語言

問題描述

5 名學生,3 門課程(英語、高數、C語言)。輸入所有成績,計算並輸出每位學生的總分與平均分。核心考點:二維數組行主序存儲、嵌套循環遍歷、函數參數傳遞二維數組。

標準實現

#include <stdio.h>

#define NUM_STUDENTS 5
#define NUM_COURSES  3

void calculate(const float score[][NUM_COURSES]);

int main() {
    float result[NUM_STUDENTS][NUM_COURSES];
    int i, j;

    printf("請輸入5個學生3門課分數(每行3個):\n");
    for (i = 0; i < NUM_STUDENTS; i++) {
        for (j = 0; j < NUM_COURSES; j++) {
            scanf("%f", &result[i][j]);
        }
    }

    calculate(result);
    return 0;
}

void calculate(const float score[][NUM_COURSES]) {
    float sum[NUM_STUDENTS] = {0};
    float avg[NUM_STUDENTS] = {0};
    int i, j;

    for (i = 0; i < NUM_STUDENTS; i++) {
        for (j = 0; j < NUM_COURSES; j++) {
            sum[i] += score[i][j];
        }
        avg[i] = sum[i] / NUM_COURSES;
    }

    for (i = 0; i < NUM_STUDENTS; i++) {
        printf("第%d人: 總分=%.2f 平均=%.2f\n", i+1, sum[i], avg[i]);
    }
}

核心技術點深度解析

1. 二維數組作為函數參數


// 正確:第二維必須指定,第一維可省略
void calculate(const float score[][NUM_COURSES]);
void calculate(const float (*score)[NUM_COURSES]);  // 等價指針寫法

// 錯誤:兩維都不可省略
void calculate(float score[][]);  // 編譯錯誤
void calculate(float **score);    // 語義不同!指向指針的指針,非連續內存

原理:C 語言二維數組在內存中連續存儲(行主序),編譯器需知道每行長度(第二維)才能計算偏移:score[i][j] ≡ *(score + i*NUM_COURSES + j)。

2. const 正確性

const float score[][NUM_COURSES] 承諾函數不修改輸入數組,編譯器會檢查違規寫入,體現防禦性編程。

3. 全局循環變量的弊端

原代碼將 i, j 定義為全局變量——極差實踐:

  • 污染全局命名空間;
  • 破壞函數獨立性(不可重入、線程不安全);
  • 難以調試與維護。

正確做法:在最小作用域(函數內、循環初始化句)聲明:for (int i = 0; ...) (C99)。

進階擴展:結構體封裝學生信息


typedef struct {
    char name[20];
    float scores[NUM_COURSES];
    float sum;
    float avg;
} Student;

void process_students(Student stu[], int n) {
    for (int i = 0; i < n; i++) {
        stu[i].sum = 0;
        for (int j = 0; j < NUM_COURSES; j++) {
            stu[i].sum += stu[i].scores[j];
        }
        stu[i].avg = stu[i].sum / NUM_COURSES;
    }
}

結構體版本將數據與操作封裝,擴展性強(易添加姓名、學號、排名等),是大型項目首選。

輸入驗證與錯誤處理增強


int read_scores(float arr[][NUM_COURSES], int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        printf("第%d位學生 %d 門課分數: ", i+1, cols);
        for (int j = 0; j < cols; j++) {
            if (scanf("%f", &arr[i][j]) != 1) {
                fprintf(stderr, "輸入錯誤: 第%d學生第%d科\n", i+1, j+1);
                return 0;
            }
            if (arr[i][j] < 0 || arr[i][j] > 100) {
                fprintf(stderr, "分數範圍錯誤 [0,100]: %.2f\n", arr[i][j]);
                return 0;
            }
        }
    }
    return 1;
}

總結

學生成績統計是二維數組、嵌套循環、函數參數傳遞、模塊化設計的綜合練習。關鍵收穫:

  • 二維數組參數第二維必須指定,內存連續佈局是前提;
  • 循環變量局部化,拒絕全局變量;
  • const 保護輸入數據不被修改;
  • 結構體封裝是面向對象思想在 C 中的體現,優於平行數組;
  • 輸入驗證(類型、範圍)是生產代碼必備。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved