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(" |---> Games won: %d\n", games_won); printf(" |---> 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
相关产品推荐
相关产品推荐

