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

srand类型转换精度丢失问题排查及C语言骰子游戏代码优化咨询

解决你的C语言骰子游戏问题:精度错误、代码优化、头文件用法及宏解释

让我们逐个拆解你遇到的问题,顺便帮你优化代码:

1. srand(time(NULL))的精度丢失错误原因及解决

你看到的错误implicit conversion loses integer precision: 'time_t' (aka 'long') to 'unsigned int'本质是类型不匹配:

  • time(NULL)返回的time_t类型,在多数系统上是64位长整型(long)
  • 而srand()的参数要求是unsigned int(通常是32位无符号整型)
  • 当time_t的数值超过unsigned int的范围时,直接转换会丢失高位数据,编译器就会抛出这个警告/错误

解决方法:显式强制转换,同时确保转换后的值在合法范围内:

// 简单强制转换(多数场景够用)
srand((unsigned int)time(NULL));
// 更严谨的方式,避免time_t远大于unsigned int的情况
#include <limits.h>
srand((unsigned int)(time(NULL) % UINT_MAX));

2. _CRT_SECURE_NO_WARNINGS的作用及相关报错

这个宏是微软Visual Studio编译器特有的,核心作用是:

  • 禁用编译器对"不安全"标准C库函数(比如scanf、strcpy、fopen)的警告
  • 微软认为这些函数存在缓冲区溢出风险,默认会提示你改用带_s后缀的安全版本(比如scanf_s、strcpy_s)

相关报错原因:

  • 如果没定义这个宏就使用scanf等函数,VS会抛出类似C4996: 'scanf': This function or variable may be unsafe的警告/错误
  • 注意:这个宏必须在包含任何头文件之前定义,否则不会生效(你的代码开头写法是对的)

3. 你的骰子游戏代码优化方案

先看修正后的完整代码,再讲关键优化点:

#define _CRT_SECURE_NO_WARNINGS
#define MAX_CHIPS 400
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h> // 用于UINT_MAX

void display_details(void);
int throw_die(void); // 修正函数名拼写:throws_die -> throw_die(更符合命名习惯)
void get_player_name(char* name);
int get_valid_bet(int current_chips);
void print_game_stats(const char* player_name, int games_played, int games_won, int games_lost, int current_chips);

int main() {
    int die1, die2, throw_sum;
    int point_to_make;
    int games_played = 0;
    int games_won = 0;
    int games_lost = 0;
    int current_chips = MAX_CHIPS;
    int bet_chips;
    char player_name[30];
    char play_again;

    display_details();
    srand((unsigned int)(time(NULL) % UINT_MAX));

    printf("Would you like to play Test your luck [y|n]?\n");
    scanf(" %c", &play_again);

    while ((play_again == 'y') && (current_chips > 0)) {
        if (games_played == 0) {
            get_player_name(player_name);
            printf("Hi %s!\n", player_name);
        }
        games_played++; // 简化写法,替代 games_played = games_played +1

        printf("Number of chips: %d\n", current_chips);
        bet_chips = get_valid_bet(current_chips);

        // 第一次掷骰子
        die1 = throw_die();
        die2 = throw_die();
        throw_sum = die1 + die2;
        printf("You Got: %d + %d = %d\n", die1, die2, throw_sum);

        // 修正Craps规则:初始掷11是赢,10属于点数(原代码错误地把10判定为输)
        if (throw_sum == 7 || throw_sum == 11) {
            games_won++;
            current_chips += bet_chips;
            printf("XXXXX Winner! d(^_^) XXXXX\n");
        } else if (throw_sum == 2 || throw_sum == 3 || throw_sum == 12) {
            games_lost++;
            current_chips -= bet_chips;
            printf("XXXXX Loser! :( XXXXX\n");
        } else {
            point_to_make = throw_sum;
            printf("Points to make is: %d\n", point_to_make);

            // 后续掷骰子直到赢或输,用do-while更简洁
            do {
                die1 = throw_die();
                die2 = throw_die();
                throw_sum = die1 + die2;
                printf(" |--->> Spinned: %d + %d = %d\n", die1, die2, throw_sum);
            } while (throw_sum != point_to_make && throw_sum != 7);

            if (throw_sum == point_to_make) {
                printf("XXXXX Winner! (x2 the bet) XXXXX\n");
                current_chips += 2 * bet_chips;
                games_won++;
            } else {
                games_lost++;
                current_chips -= bet_chips;
                printf("XXXXX Loser!:( XXXXX\n");
            }
        }

        if (current_chips > 0) {
            printf("You now have %d chips.\n", current_chips);
            printf("============================\n\n");
            printf("Play Again %s [y|n]? ", player_name);
            scanf(" %c", &play_again);
            printf("============================\n");
        } else {
            printf("you're out of chips.\n");
            printf("XXXXX GG TRY AGAIN NEXT TIME XXXXX\n");
            break;
        }
    }

    print_game_stats(player_name, games_played, games_won, games_lost, current_chips);

    return 0;
}

void display_details(void) {
    printf("File :.... assignment.c\n");
    printf("Author :.... \n");
    printf("Stud ID :.... \n");
    printf("Email ID :.... \n");
    printf("This is my own work as defined by the \n");
    printf("University's Academic Misconduct Policy.\n");
}

int throw_die(void) {
    // 生成1-6的随机数,写法更严谨:rand()返回[0, RAND_MAX],取模6得[0,5],加1得[1,6]
    return (rand() % 6) + 1;
}

void get_player_name(char* name) {
    printf("A new challenger! What is your name?\n");
    // 语法修正:数组名本身是指针,不需要加&,原代码的&PlayerName是错误的
    scanf(" %s", name);
}

int get_valid_bet(int current_chips) {
    int bet;
    printf("Place your bet:\n ");
    // 增加输入验证:确保输入是整数,且在合法范围内,避免非数字输入导致死循环
    while (scanf("%d", &bet) != 1 || bet < 0 || bet > current_chips) {
        // 清理输入缓冲区的无效字符
        while (getchar() != '\n');
        printf("Oops....You can only bet the chips you have.. (0-%d)!\n", current_chips);
        printf("Place your bet: \n");
    }
    return bet;
}

void print_game_stats(const char* player_name, int games_played, int games_won, int games_lost, int current_chips) {
    if (games_played == 0) {
        printf("Oh well.... better luck next time!\n");
    } else {
        printf("%s played %d %s and is cashing out with %d chips!\n", 
               player_name, games_played, games_played == 1 ? "game" : "games", current_chips);
        printf(" |---&gt; Games won: %d\n", games_won);
        printf(" |---&gt; Games lost: %d\n", games_lost);
        printf("\nThanks for playing, come again to test that luck of yours %s!\n", player_name);
    }
}

主要优化点:

  • 修正游戏规则错误:原代码把初始掷10判定为输,不符合Craps游戏规则(正确规则:初始掷7/11赢,2/3/12输,其他为点数)
  • 代码模块化:把获取用户名、验证下注、打印统计信息拆成单独函数,让main逻辑更清晰易读
  • 输入安全性:增加对下注输入的验证,处理非数字输入的情况,避免程序死循环
  • 语法修正:原代码中scanf(" %s", &PlayerName)错误,数组名不需要加&,已修正
  • 简化代码:用games_played++、current_chips += bet_chips等简化写法替代冗余赋值
  • 统计信息优化:用三元运算符处理"game/games"的单复数,减少重复代码

4. iostream等C++头文件的用法

iostream是C的标准输入输出头文件,如果你想用C重写这个游戏,会比C更简洁安全,以下是关键用法:

基本替换规则:

  • 替换C的头文件为C++对应版本:
    // C头文件 -> C++头文件
    #include <stdio.h> -> #include <iostream>
    #include <stdlib.h> -> #include <cstdlib>
    #include <time.h> -> #include <ctime>
    
  • 使用C++的输入输出流:
    // 输出(代替printf)
    std::cout << "Hi " << player_name << "!" << std::endl;
    // 输入(代替scanf)
    std::cin >> player_name;
    
  • 如果你不想每次写std::,可以在头文件后加:
    using namespace std;
    
    这样直接写cout、cin即可。

更安全的字符串处理:

用C++的std::string代替char数组,彻底避免缓冲区溢出问题:

#include <string> // 必须包含这个头文件

std::string player_name;
cout << "A new challenger! What is your name?\n";
cin >> player_name;
cout << "Hi " << player_name << "!\n";

C++版本核心逻辑示例:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <limits> // 用于清理输入缓冲区

const int MAX_CHIPS = 400;

void display_details();
int throw_die();

int main() {
    srand(static_cast<unsigned int>(time(nullptr) % UINT_MAX));
    std::string player_name;
    int current_chips = MAX_CHIPS;
    char play_again = 'y';
    int games_played = 0, games_won = 0, games_lost = 0;

    display_details();
    std::cout << "Would you like to play Test your luck [y|n]?\n";
    std::cin >> play_again;

    while (play_again == 'y' && current_chips > 0) {
        if (games_played == 0) {
            std::cout << "A new challenger! What is your name?\n";
            std::cin >> player_name;
            std::cout << "Hi " << player_name << "!\n";
        }
        games_played++;

        std::cout << "Number of chips: " << current_chips << "\nPlace your bet:\n";
        int bet_chips;
        while (!(std::cin >> bet_chips) || bet_chips < 0 || bet_chips > current_chips) {
            std::cin.clear(); // 清除输入错误状态
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 清理缓冲区无效字符
            std::cout << "Oops....You can only bet the chips you have.. (0-" << current_chips << ")!\nPlace your bet:\n";
        }

        int die1 = throw_die(), die2 = throw_die();
        int throw_sum = die1 + die2;
        std::cout << "You Got: " << die1 << " + " << die2 << " = " << throw_sum << "\n";

        if (throw_sum == 7 || throw_sum == 11) {
            games_won++;
            current_chips += bet_chips;
            std::cout << "XXXXX Winner! d(^_^) XXXXX\n";
        } else if (throw_sum == 2 || throw_sum == 3 || throw_sum == 12) {
            games_lost++;
            current_chips -= bet_chips;
            std::cout << "XXXXX Loser! :( XXXXX\n";
        } else {
            int point_to_make = throw_sum;
            std::cout << "Points to make is: " << point_to_make << "\n";
            do {
                die1 = throw_die();
                die2 = throw_die();
                throw_sum = die1 + die2;
                std::cout << " |--->> Spinned: " << die1 << " + " << die2 << " = " << throw_sum << "\n";
            } while (throw_sum != point_to_make && throw_sum != 7);

            if (throw_sum == point_to_make) {
                std::cout << "XXXXX Winner! (x2 the bet) XXXXX\n";
                current_chips += 2 * bet_chips;
                games_won++;
            } else {
                games_lost++;
                current_chips -= bet_chips;
                std::cout << "XXXXX Loser!:( XXXXX\n";
            }
        }

        if (current_chips > 0) {
            std::cout << "You now have " << current_chips << " chips.\n";
            std::cout << "============================\n\nPlay Again " << player_name << " [y|n]? ";
            std::cin >> play_again;
            std::cout << "============================\n";
        } else {
            std::cout << "you're out of chips.\nXXXXX GG TRY AGAIN NEXT TIME XXXXX\n";
            break;
        }
    }

    if (games_played == 0) {
        std::cout << "Oh well.... better luck next time!\n";
    } else {
        std::cout << player_name << " played " << games_played << (games_played == 1 ? " game" : " games") 
                  << " and is cashing out with " << current_chips << " chips!\n";
        std::cout << " |--->> Games won: " << games_won << "\n |--->> Games lost: " << games_lost << "\n";
        std::cout << "\nThanks for playing, come again to test that luck of yours " << player_name << "!\n";
    }

    return 0;
}

void display_details() {
    std::cout << "File :.... assignment.cpp\n";
    std::cout << "Author :.... \n";
    std::cout << "Stud ID :.... \n";
    std::cout << "Email ID :.... \n";
    std::cout << "This is my own work as defined by the \n";
    std::cout << "University's Academic Misconduct Policy.\n";
}

int throw_die() {
    return (rand() % 6) + 1;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:08:44