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

C語言猜拳遊戲積分邏輯陷阱:局部變量重置導致計分失效的解決方案

     編輯:關於C語言

C語言猜拳遊戲積分邏輯陷阱:局部變量重置導致計分失效的解決方案

初學 C 語言時編寫「猜拳(石頭剪刀布)」遊戲是經典練習。許多初學者會遇到一個令人困惑的問題:**明明在函數裡計算了勝負並返回分數,為什麼總分永遠不對?** 本文剖析「函數局部變量隨調用重置」的核心成因,並給出正確的跨函數積分累計方案。

一、 錯誤代碼復現:為什麼分數不累加?

// 錯誤版本:compare 函數內部計分
int compare(int x, int y) {
    int j = 0; // ❌ 關鍵錯誤:每次調用函數,j 都重新初始化為 0!
    
    if (x < 3 && x > 0) {
        if (y - x == 0) {
            printf("平手!\n");
        } else if (y - x == 1 || x - y == 1) { // 差值為 1
            if (x > y) { printf("你贏了!\n"); j++; }
            else { printf("電腦贏了!\n"); j--; }
        } else if (y - x == 2 || x - y == 2) { // 差值為 2
            if (x > y) { printf("電腦贏了!\n"); j--; }
            else { printf("你贏了!\n"); j++; }
        }
    } else {
        printf("輸入錯誤!\n");
    }
    return j; // 返回單局得分:+1, 0, -1
}

問題本質: j 是 compare 的**自動局部變量**,存儲在棧幀中。每次 main 迴圈調用 compare,棧幀重建,j 重置為 0。函數返回的只是**單局得分**,而非累計總分。

二、 正確架構:主函數掌握總分,子函數只負責判斷

// 正確版本:compare 只返回單局結果
int compare(int player, int computer) {
    if (player < 1 || player > 3) return -99; // 錯誤碼
    
    int diff = computer - player; // 1:剪刀 2:石頭 3:布
    if (diff == 0) return 0;      // 平手
    if (diff == 1 || diff == -2) return -1; // 電腦贏
    return 1;                     // 玩家贏
}

int main() {
    srand((unsigned)time(NULL)); // 種子
    int total_score = 0;         // ✅ 總分變量在 main 中,生命週期覆蓋整個遊戲
    int rounds = 5;
    
    for (int i = 0; i < rounds; i++) {
        int player, computer;
        printf("請出拳 (1剪刀 2石頭 3布): ");
        scanf("%d", &player);
        computer = rand() % 3 + 1;
        printf("電腦出: %d\n", computer);
        
        int round_score = compare(player, computer);
        if (round_score == -99) { printf("輸入無效!\n"); i--; continue; }
        
        total_score += round_score; // ✅ 在 main 累加
        printf("本局得分: %d, 總分: %d\n", round_score, total_score);
    }
    
    if (total_score > 0) printf("最終你贏了!");
    else if (total_score < 0) printf("最終電腦贏了!");
    else printf("最終平手!");
    return 0;
}

三、 核心原理圖解:變量生命週期與作用域

變量定義位置存儲區生命週期作用域能否跨調用保持值
j (錯誤版)函數內部棧單次函數調用函數內部❌ 每次調用重置
total_score (正確版)main 內部棧整個 main 執行期間main 內部✅ 迴圈內持久保持
靜態局部變量 static int j函數內部全域/靜態區程序整個運行期間函數內部✅ 但破壞函數純粹性,不推薦
全域變量函數外部全域/靜態區程序整個運行期間全文件可見✅ 但污染命名空間,不推薦

四、 進階重構:狀態封裝與擴展性

隨著遊戲複雜度增加(如多玩家、歷史記錄、不同規則),建議引入狀態結構體:

typedef struct {
    int player_score;
    int computer_score;
    int round;
    int history[100]; // 記錄每局結果
} GameState;

void play_round(GameState *state, int player_move) {
    // ... 邏輯 ...
    state->history[state->round++] = round_result;
    // 更新分數
}

這樣實現了狀態與邏輯分離,便於單元測試、存檔讀檔、多實例運行。

總結

「函數內部計分變量重置」是 C 語言初學者**對變量存儲類別(自動 vs 靜態)與作用域理解不足**的典型表現。記住鐵律:**數據的所有權歸屬於負責其生命週期的函數/模塊**。主迴圈擁有遊戲總分,子函數只負責單次邏輯判斷,這是結構化程式設計的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved