文档章节

C Primer Plus 第12章 12.5 掷骰子

idreamo
 idreamo
发布于 2016/12/13 06:23
字数 1308
阅读 38
收藏 0

掷骰子最普遍的形式是用两个6面骰子。

计算机可以设计一种具有任意面数的骰子,先从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 <stdlib.h>        /*为rand()函数提供原型*/
int rollem(int sides)
{
    int roll;
    
    roll = rand()%sides + 1;
    return roll;
}

进一步,我们想实现这样的功能:它允许掷任意个骰子,并且返回点数总和。程序清单12.11实现了这样的功能。

/*diceroll.c --掷骰子的模拟程序*/
#include "diceroll.h"
#include <stdio.h>
#include <stdlib.h>  /*为rand()函数提供类库*/

int roll_count = 0;  /*外部链接*/

static int rollem(int sides)  /*这个文件的私有函数*/
{
    int roll;

    roll=rand()%sides+1;
    ++roll_count;  /*计数函数调用*/
    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;
}

这个文件中加入了一些新东西。首先,它把rollem()变成由该文件私有的函数,这个函数用于辅助roll_n_dice();其次,为了举例说明外部链接如何工作,文件声明了一个外部变量roll_count,这个变量跟踪记录函数rollem()的调用次数。例子本身有一点不妥,但它显示了外部变量的如何工作的。

再次,文件包含下面的语句:

#include "diceroll.h"

如果使用诸如rand()的标准库函数,您需要在程序中包含标准头文件(对rand()来说是stdlib.h),而不是声明函数,因为头文件中已经包含了正确的声明。我们将效仿这一做法,提供一个头文件diceroll.h以供函数roll_n_dice()使用。将文件名置于双引号而非尖括号中, 是为了指示编译器在本地寻找文件,而不是到编译器存放标准头文件的标准位置去寻找文件。“在本地寻找”的意义取决于具体的C实现。一些常见解释是将头文件与源代码文件放在同一个目录或文件夹中。程序清单12.12显示了该头文件的内容。

程序清单12.12 diceroll.h文件

//diceroll.h

extern int roll_count;

int roll_n_dice(int dice,int sides);

这个头文件中包含函数原型声明一和个extern声明。因为文件diceroll.c包含了这一头文件,它也就实际上包含了roll_count的两个声明:

extern int roll_count;    //来自头文件

int roll_count = 0;       //来自源代码文件

这是可以的,一个变量只可以有一个定义声明,但使用extern的声明是一个引用声明,这样的声明想用多少就可以用多少。

使用roll_n_dice()的程序也应该包含这一头文件。这样做不仅仅提供roll_n_dice()原型,还使得roll_count对程序可用。程序清单12.13证明了这些。

//manydice.c  --多次掷骰子的模拟程序
//与diceroll.c一起编译
#include<stdio.h>
#include<stdlib.h>        //为srand()提供原型
#include<time.h>          //为time()提供原型
#include"dicerlll.h"      //为roll_n_dice()和roll-count提供原型

int main(void)
{
    int dice ,roll;
    int sides;

    srand((unsigned int )time(0));    //随机化种子
    printf("Enter the number of sides per die,0 to stop.\n");
    while(scanf("%d",&sides)==1 && sides>0)
    {
        printf("How many dice?\n");
        scanf("%d",&dice);
        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);    /*使用外部变量*/
    printf("Good Fortune To You!\n");
    return 0;
}

将程序清单12.13与包含程序清单12.11的文件一起编译。为了简化问题,把程序清单12.11、12.12和12.13放在同一文件中或同一目录下。运行最后得到的程序,输出应该像下面这样:

Enter the number of sides per die,0 to stop.
6
How many dice?
2
You have rolled a 12 using 2 6-sided dece.
How many sides?Enter 0 to stop.
6
How many dice?
2
You have rolled a 4 using 2 6-sided dice.
How many sides?Enter 0 to stop.
6
How many dice?
2
You have rolled a 5 using 2 6-sided dice.
How many sides?Enter 0 to stop.
0
The rollem() funcation was called 6 times.
GOOD FORRUNE TO YOU!

因为程序使用srand()来随机确定随机数种子,所以大多数情况下,即使有相同的输入也不可能得到相同的输出。注意,manydice.c中的main()确实可以访问diceroll.c中定义的变量roll_count。

可以使用多种方式使用roll_n_dice()。对于sides为2的情形,程序模仿掷硬币,面朝上为2,背朝上为1.您可以很容易地修改程序来像显示总体结果那样显示个别结果,或者建一个掷双骰子赌博模拟器。

© 著作权归作者所有

idreamo
粉丝 18
博文 139
码字总数 224743
作品 0
青岛
产品经理
私信 提问
书单及进度(每日更新2015-7-13)

jQuery Mobile Web Development Essentials.pdf 写的很好5 Apache Cordova 3 Programming.pdf 写的比较啰嗦,不过找不到其它的书了3 Web Development with Node and Express.pdf ING(这个已经......

cyper
2014/05/14
231
7
C Primer Plus 第12章 12.2 存储类说明符

C语言中有5个关于存储类说明符的关键字,它们是auto、register、static、extern以及typedef。关键字typedef与内存存储无关,由于语法原因被归入此类。特别地,不可以在一个声明中使用一个以上...

idreamo
2016/11/19
20
0
Python这么强大, 怎样才能快速入坑?

作为一种年轻的编程语言,Python为何能在短短几年的时间内就以迅雷不及掩耳之势驰骋编程界?答案很简单,在人工智能时代,AlphaGo 都在使用的 Python语言,是最接近 AI 的编程语言。 随着Pyt...

bodasisiter
2018/08/23
270
0
C Primer Plus(5版)第8章编程题1_重定向实现

小伙伴们,对C语言编程有疑问的,可以加微信交流:poo_poo或者扫描我的头像,验证时请注明是“知友” 一、题目描述 本题是第8章编程题的第一道题,题目如下: 二、题目及思路分析 从题述来看...

石家的鱼
2017/07/11
0
0
关东升的《从零开始学Swift》第2版已经出版

关东升的《从零开始学Swift》第2版已经出版 大家好: 苹果2015WWDC大会发布了Swift2.0,它较之前的版本Swift1.x有很大的变化,所以我即将出版《从零开始学Swift》 《从零开始学Swift》将在《...

tony关东升
2016/02/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
昨天
6
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
昨天
7
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
昨天
6
0
【技术分享】TestFlight测试的流程文档

上架基本需求资料 1、苹果开发者账号(如还没账号先申请-苹果开发者账号申请教程) 2、开发好的APP 通过本篇教程,可以学习到ios证书申请和打包ipa上传到appstoreconnect.apple.com进行TestF...

qtb999
昨天
10
0
再见 Spring Boot 1.X,Spring Boot 2.X 走向舞台中心

2019年8月6日,Spring 官方在其博客宣布,Spring Boot 1.x 停止维护,Spring Boot 1.x 生命周期正式结束。 其实早在2018年7月30号,Spring 官方就已经在博客进行过预告,Spring Boot 1.X 将维...

Java技术剑
昨天
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部