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

C語言實現購物抽獎程序:條件判斷與隨機數應用實例

     編輯:C 語言問答

C語言實現購物抽獎程序:條件判斷與隨機數應用實例

「某城市舉辦購物有獎活動,購物額≥200元可參加抽獎,抽到1或9號獲獎」——這是典型的條件分支與用戶交互綜合練習。本文提供標準實現、健壯增強、隨機數進階、擴展重構四個版本,展示從「能跑」到「工程級」的代碼演進。

一、標準版:題目要求直接實現


#include 

int main() {
    double amount = 0.0;
    int lottery_num = 0;
    
    printf("請輸入購物金額:");
    if (scanf("%lf", &amount) != 1) {
        printf("輸入錯誤:請輸入數字\n");
        return 1;
    }
    
    if (amount < 200) {
        puts("對不起,您不能參加抽獎。");
    } else {
        printf("輸入10以內的任意一個值 (1-10):");
        if (scanf("%d", &lottery_num) != 1) {
            printf("輸入錯誤:請輸入整數\n");
            return 1;
        }
        
        if (lottery_num == 1 || lottery_num == 9) {
            puts("恭喜您獲獎!");
        } else {
            puts("感謝您的參與,謝謝!");
        }
    }
    
    return 0;
}

二、健壯版:完整輸入驗證與錯誤恢復


#include 
#include 

// 安全讀取一行並解析double
int read_double(const char *prompt, double *out) {
    char buf[256];
    while (1) {
        printf("%s", prompt);
        if (!fgets(buf, sizeof(buf), stdin)) return 0; // EOF
        
        char *endptr;
        double val = strtod(buf, &endptr);
        if (endptr != buf && (*endptr == '\n' || *endptr == '\0')) {
            *out = val;
            return 1;
        }
        printf("輸入無效,請重新輸入數字。\n");
    }
}

// 安全讀取整數並校驗範圍
int read_int_range(const char *prompt, int *out, int min, int max) {
    char buf[256];
    while (1) {
        printf("%s", prompt);
        if (!fgets(buf, sizeof(buf), stdin)) return 0;
        
        char *endptr;
        long val = strtol(buf, &endptr, 10);
        if (endptr != buf && (*endptr == '\n' || *endptr == '\0') 
            && val >= min && val <= max) {
            *out = (int)val;
            return 1;
        }
        printf("輸入無效,請輸入 %d 到 %d 之間的整數。\n", min, max);
    }
}

int main() {
    double amount;
    int lottery_num;
    
    if (!read_double("請輸入購物金額:", &amount)) return 1;
    
    if (amount < 200) {
        puts("對不起,您不能參加抽獎。");
        return 0;
    }
    
    if (!read_int_range("請輸入抽獎號碼 (1-10):", &lottery_num, 1, 10)) return 1;
    
    if (lottery_num == 1 || lottery_num == 9) {
        puts("恭喜您獲獎!");
    } else {
        puts("感謝您的參與,謝謝!");
    }
    
    return 0;
}

三、進階版:真隨機抽獎模擬 (srand/rand)


#include 
#include 
#include 

// 生成 [min, max] 範圍內均勻分布隨機整數
int rand_range(int min, int max) {
    // 避免模數偏差:拒絕採樣
    int range = max - min + 1;
    int limit = RAND_MAX - (RAND_MAX % range);
    int r;
    do {
        r = rand();
    } while (r >= limit);
    return min + r % range;
}

int main() {
    // 僅在程序啟動時播種一次!
    srand((unsigned)time(NULL));
    
    double amount;
    printf("請輸入購物金額:");
    if (scanf("%lf", &amount) != 1) return 1;
    
    if (amount < 200) {
        puts("對不起,您不能參加抽獎。");
        return 0;
    }
    
    puts("正在為您抽獎...");
    int winning_num = rand_range(1, 10);
    printf("開獎號碼:%d\n", winning_num);
    
    if (winning_num == 1 || winning_num == 9) {
        puts("恭喜您獲獎!");
    } else {
        puts("感謝您的參與,謝謝!");
    }
    
    return 0;
}

四、工程版:模組化、可配置、可測試


// lottery.h
#ifndef LOTTERY_H
#define LOTTERY_H

typedef enum { LOTTERY_OK = 0, LOTTERY_ERR_INPUT, LOTTERY_ERR_RANGE } LotteryErr;

typedef struct {
    double threshold;       // 參與門檻
    int *winning_numbers;   // 中獎號碼數組
    int winning_count;      // 中獎號碼個數
    int min_num;            // 號碼範圍下界
    int max_num;            // 號碼範圍上界
} LotteryConfig;

typedef struct {
    int drawn_number;       // 抽中的號碼
    int is_winner;          // 是否中獎
} LotteryResult;

// 初始化配置 (可從文件/環境變量讀取)
void lottery_init_config(LotteryConfig *cfg);

// 執行抽獎 (分離邏輯與IO,便於單元測試)
LotteryErr lottery_draw(const LotteryConfig *cfg, double amount, int *drawn_num, int *is_winner);

// 交互式運行
void lottery_run_interactive(const LotteryConfig *cfg);

#endif

// lottery.c
#include "lottery.h"
#include 
#include 
#include 

static int seeded = 0;

void lottery_init_config(LotteryConfig *cfg) {
    cfg->threshold = 200.0;
    static int default_winning[] = {1, 9};
    cfg->winning_numbers = default_winning;
    cfg->winning_count = 2;
    cfg->min_num = 1;
    cfg->max_num = 10;
}

static int is_winning_number(const LotteryConfig *cfg, int num) {
    for (int i = 0; i < cfg->winning_count; i++) {
        if (cfg->winning_numbers[i] == num) return 1;
    }
    return 0;
}

LotteryErr lottery_draw(const LotteryConfig *cfg, double amount, int *drawn_num, int *is_winner) {
    if (amount < cfg->threshold) return LOTTERY_ERR_RANGE;
    
    if (!seeded) {
        srand((unsigned)time(NULL));
        seeded = 1;
    }
    
    int range = cfg->max_num - cfg->min_num + 1;
    int limit = RAND_MAX - (RAND_MAX % range);
    int r;
    do { r = rand(); } while (r >= limit);
    *drawn_num = cfg->min_num + r % range;
    *is_winner = is_winning_number(cfg, *drawn_num);
    
    return LOTTERY_OK;
}

void lottery_run_interactive(const LotteryConfig *cfg) {
    double amount;
    printf("請輸入購物金額:");
    if (scanf("%lf", &amount) != 1) return;
    
    int drawn, winner;
    LotteryErr err = lottery_draw(cfg, amount, &drawn, &winner);
    if (err == LOTTERY_ERR_RANGE) {
        puts("對不起,您不能參加抽獎。");
        return;
    }
    
    printf("開獎號碼:%d\n", drawn);
    if (winner) puts("恭喜您獲獎!");
    else puts("感謝您的參與,謝謝!");
}

// main.c
#include "lottery.h"

int main() {
    LotteryConfig cfg;
    lottery_init_config(&cfg);
    lottery_run_interactive(&cfg);
    return 0;
}

五、單元測試示例 (分離邏輯後易測試)


// test_lottery.c
#include "lottery.h"
#include 
#include 

void test_threshold() {
    LotteryConfig cfg;
    lottery_init_config(&cfg);
    int drawn, winner;
    
    // 低於門檻
    assert(lottery_draw(&cfg, 199.9, &drawn, &winner) == LOTTERY_ERR_RANGE);
    
    // 等於門檻
    assert(lottery_draw(&cfg, 200.0, &drawn, &winner) == LOTTERY_OK);
    assert(drawn >= 1 && drawn <= 10);
    
    printf("門檻測試通過\n");
}

void test_winning_numbers() {
    LotteryConfig cfg;
    lottery_init_config(&cfg);
    
    // 手動設置測試號碼 (需修改lottery_draw支持注入測試號碼)
    // 這裡演示邏輯測試思路
    assert(is_winning_number(&cfg, 1) == 1);
    assert(is_winning_number(&cfg, 9) == 1);
    assert(is_winning_number(&cfg, 5) == 0);
    
    printf("中獎號碼邏輯測試通過\n");
}

int main() {
    test_threshold();
    test_winning_numbers();
    printf("所有測試通過!\n");
    return 0;
}

六、關鍵知識點總結

知識點標準版健壯版進階版工程版
輸入處理scanf直接讀取fgets+strtod/strtol循環驗證scanf簡化模組化輸入函數
隨機數用戶輸入模擬用戶輸入模擬srand/rand真隨機拒絕採樣避免偏差
代碼結構單main函數單main+工具函數單main分層架構、接口分離
可測試性無低低高 (邏輯與IO分離)
可配置性硬編碼硬編碼硬編碼配置結構體、外部化

從簡單的`if-else`入手,逐步引入「輸入驗證、隨機數、模組化、配置外部化、測試驅動」,這就是C語言程序從「練習題」進化為「產品級代碼」的必經之路。

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