• C Primer Plus(6) 中文版 第12章 存储类别、链接和内存管理 12.3 掷骰子


    12.3 掷骰子
    最普遍的是使用两个6面骰子。在一些冒险游戏中,会使用5种骰子:4面、6面、8面、12面和20面。聪明的古希腊人证明了只有5种正多面体,它们的所有面都具有相同的形状和大小。各种不同类型的骰子就是根据这些正多面体发展而来。也可以做成其他面数的,但是其所有的面都不会
    相等,因此各个面朝上的几率就不同。
    计算机计算不用考虑几何的限制,所以可以设计任何面数的电子骰子。我们先从6面开始。
    想获得1~6的随机数。然而,rand()生成的随机数在0~RAND_MAX之间。RAND_MAX被定义在stdlib.h中,其值通常是INT_MAX。因此,需要进行一些调整,方法如下。
    1.把随机数求模6,获得的整数在0~5之间。
    2.结果加1,新值在1~6之间。
    3.为方便以后扩展,把第1步中的数字6替换成骰子面数。
    #include /*提供rand()的原型*/
    int rollem( int sides ){
        int roll;
        
        roll = rand() % sides + 1;
        return roll;

    我们还想用一个函数用于提示用户选择任意面数的骰子,并返回点数总和。
    //diceroll.h
    extern int roll_count;

    int roll_n_dice(int dice, int sides);
    /* diceroll.c -- dice role simulation */
    /* compile with manydice.c           */
    #include "diceroll.h"
    #include
    #include           /* for library rand()   */

    int roll_count  = 0;          /* external linkage     */

    static int rollem(int sides)  /* private to this file */
    {
        int roll;
        
        roll = rand() % sides + 1;
        ++roll_count;             /* count function calls */
        
        return roll;
    }

    int roll_n_dice(int dice, int sides)
    {
        int d;
        int total = 0;
        if (sides < 2)
        {
            printf("Need at least 2 sides.\n");
            return -2;
        }
        if (dice < 1)
        {
            printf("Need at least 1 die.\n");
            return -1;
        }
        
        for (d = 0; d < dice; d++)
            total += rollem(sides);
        
        return total;

    /* manydice.c -- multiple dice rolls                    */
    /* compile with diceroll.c                              */
    #include
    #include              /* for library srand() */
    #include                /* for time()          */
    #include "diceroll.h"            /* for roll_n_dice()   */
    /* and for roll_count  */
    int main(void)
    {
        int dice,roll;
        int sides;
        int status;
        
        srand((unsigned int) time(0)); /* randomize seed      */
        printf("Enter the number of sides per die, 0 to stop.\n");
        while (scanf("%d", &sides) == 1 && sides > 0 )
        {
            printf("How many dice?\n");
            if ((status =scanf("%d", &dice)) != 1)
            {
                if (status == EOF)
                    break;             /* exit loop           */
                else
                {
                    printf("You should have entered an integer.");
                    printf(" Let's begin again.\n");
                    while (getchar() != '\n')
                        continue;     /* dispose of bad input */
                    printf("How many sides? Enter 0 to stop.\n");
                    continue;         /* new loop cycle       */
                 }
            }
            roll = roll_n_dice(dice, sides);
            printf("You have rolled a %d using %d %d-sided dice.\n",
                   roll, dice, sides);
            printf("How many sides? Enter 0 to stop.\n");
        }
        printf("The rollem() function was called %d times.\n",
               roll_count);           /* use extern variable */
        
        printf("GOOD FORTUNE TO YOU!\n");
        
        return 0;
    }

    /* 输出:

    */

    direroll.c加入了新元素。第一,rollem函数属于该文件私有。第二,为了演示外部链接的特性,该文件声明了一个外部变量roll_count。该变量统计调用rollem()函数的次数。这样设计有点蹩脚,仅为了演示外部变量的特性。第三,该文件包含以下预处理指令:
    #include "direroll.h"
    如果使用标准库函数,要在当前文件中包含标准头文件,而不是声明该函数。因为头文件中已经包含了正确的函数原型。我们效仿这一做法。把文件名放在双引号中而不是尖括号中,指示编译器在本地查找文件,而不是到编译器存储标准头文件的位置去查找文件。“本地查找”的含义取决于具体的实现。一些常见的实现把头文件与源代码文件或工程文件(如果编译器使用它们的话)放在同样的目录或文件中。 
    //diceroll.h
    extern int roll_count;

    int roll_n_dice(int dice, int sides);
    该头文件包含了一个函数原型和一个extern声明。由于direroll.c文件包含了该文件,direroll.c实际上包含了roll_count的两个声明:
    extern int roll_count; //头文件中的声明(引用式声明)
    int roll_count = 0; //源代码文件中的声明(定义式声明)
    这样做没问题。一个变量只能有一个定义时声明,但是带extern的声明时引用式声明,可以有多个引用式声明。
    因为该程序使用了srand()随机生成随机数种子,所以在大多数情况下,即使输入相同也很难得到相同的输出。注意,manydice.c中的main()访问了定义在direroll.c中的roll_count变量。
    scanf( "%d", &sides ) == 1;
    当输入遇到EOF时,scanf( "%d", &sides ) == 1;的结果为真。
    可以通过多种方式使用roll_n_dice()。sides等于2时,程序模仿掷硬币,“正面朝上”为2,“反面朝上”为1(或者反过来也行)。
    rand1()或rand()(不是rollem())还可以用来创建一个猜数字程序,让计算机选定一个数字,你来猜。读者如果感兴趣可以自己编写这个程序。

    /*
    ** 猜数字游戏 
    */
    #include
    #include
    #include  

    int main( void ){
        int number;
        int guess;
        
        srand( (unsigned int)0 );
        number = rand() % 100 + 1;
        do{
            printf( "Please input a number between 1 and 100(inclusive):" );
            scanf( "%d", &guess );
            if( number == guess ){
                printf( "the answer of guess is right!\n" );
            } else if( number > guess ){
                printf( "the answer of guess is smaller than number!\n" );
            } else{
                printf( "the answer of guess is larger than number!\n" );
            }
        } while( number != guess );
        
        return EXIT_SUCCESS;
    }
    /* 输出:

    */ 

  • 相关阅读:
    设计模式之策略模式
    react 相关
    【Text2SQL】评估 LLM 的 Text2SQL 能力
    java虚拟机常用工具
    想玩转监控神器Prometheus吗?
    哈希思想的应用 - 位图,布隆过滤器
    基于Vue+SpringBoot的大病保险管理系统 开源项目
    电脑使用技巧分享  电脑小白们快收藏
    一步步撸脚本监控
    大气污染数据系统
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126378488