初识C语言3——函数(以猜数字游戏为例)

简介: 初识C语言3——函数(以猜数字游戏为例)

前言

 想玩一个数字范围在1~100的猜数字游戏,根据自己浅薄的知识怎样把这个游戏写出来呢?

 一个简单的猜数字游戏是怎样构思又怎样逐步实现的呢?接下来请允许我为大家详细介绍一下吧!

1.大致思路

 想要实现一个猜数字游戏,说简单点,最核心的部分就是先让电脑生成一个随机数,然后再让玩家输入值猜这个随机数,程序再根据玩家输入的值与这个随机数进行比较,接着再反馈给玩家一定的提示,最终使其猜出正确的数字。

2.猜数字游戏的核心部分(生成随机数

2.1函数

 想要实现以上随机数的生成,我们必须要知道C语言中的函数。

2.1.1什么是函数?(初识C语言函数的概念)

 在数学中,我们已经知道函数的概念,简单点,假如题目中给了我们一个y=2x-1的函数,当我想知道y的值时,有了这个函数,我只需知道x的值就能得出y的值。

 C语言中的函数与数学中的函数大致相似,都是由一份数据经过一定的计算或规则得到另一份数据,为什么说大致相似,是因为它们确实又有着天壤之别。

 ‘函数’的英文为function,可是function翻译成中文又有‘功能’的意思,在C语言中,把function翻译为‘功能’或许更恰当。我们知道,一个程序的实现由多个函数组成,每一个函数负责实现一定的功能,一个程序由多个函数组成,也就是说:一个程序的实现由多个小的功能叠加而实现!

2.1.2C语言函数的定义

在C语言中,函数有以下4个组成部分:

先例举一个add函数:

返回类型:一个函数可以返回一个值。

上图中我们计算的是两个数的和,需要返回整数,所以int是函数返回的值的数据类型。有些函数在执行完毕后不需要返回值,在这种情况下,返回类型就用关键字 void(空类型);

函数名称:这是函数的实际名称。如上图的‘Add’,函数名可以由我们直接来命名;

参数:参数就像是占位符。当函数被调用时,向参数传递一个值,比如上图中我们传递给Add函数一个x和y的值,x和y就是我们的参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。

函数体:函数主体包含一组定义函数执行任务的语句。

 2.1.3 函数的分类(以随机数的生成为例)

 函数分为库函数自定义函数

 那么库函数和自定义函数又是什么呢?本文以猜数字游戏的实现为基础,首先讲解库函数的概念,再自然而然就会引出自定义函数。

库函数

 在初识C语言1中我们就已经提到过printf函数和scanf函数,这两个函数就是库函数,库函数就是由C语言为我们提供的现成的函数,可以直接使用。事实上,为了我们在编写程序时提高效率,C语言在发布时就为我们封装好了许多函数,这些函数就是库函数。

  引到本文主题,比如在猜数字游戏中想要生成一个随机数,怎么来实现呢?这就需要用到一个库函数rand了,登录网站https://cplusplus.com我们查询一下rand函数的用法,如下图所示:

(https://cplusplus.com网站查找库函数使用方法:在首页点击右上角Legacy version切换到旧版本,在搜索框中输入函数名称查找)

接下来我们用一下rand函数生成随机数看一下:

#include <stdio.h>
#include <stdlib.h>//函数rand的头文件为stdlib.h
int main()
{
  int input = 1;
  while (input)
  {
    scanf("%d", &input);
    printf("%d\n", rand());
  }
  return 0;
}

第一次运行结果:

第二次运行结果:

不难发现,我们每次程序运行生成的随机数都如出一辙,这要是玩猜数字游戏,我记住了第一次程序运行的数据,后面再玩我都知道了随机数是什么,那这游戏玩的还有什么意思呢?

 那问题出在哪里了呢?怎么才能保证我每次程序运行的结果都不一样呢?我们再返回去看一下rand函数的用法:

可见在使用rand函数时,我们必须先引用srand函数对rand初始化:所以我们再在此基础上引用一下srand函数:

观察以上两个图,这时候又有问题了:每次生成的随机数好像也并不随机呀!我只有每次给srand函数传递一个不同的参数(就是上图中括号中的1与2),程序才能每次生成不同的随机数,那我想达到目的还要每次给你传递一个不同的参数吗?

 可是这就很矛盾了啊,我用这个函数就是为了生成随机数的,你还要我给你传递一个随机数,那我干脆自己生成随机数好了,还要你这个函数干嘛呢?

 这是为什么呢?我们函数用错了吗?方法不对吗?

 其实不是的,我们的思路没有问题,函数也没有用错,我们的问题已经解决一大半了:想正常生成随机数,无非就是随机传递给srand函数一个参数罢了,那又怎么随机给srand函数传参呢?

 时光如剑,日月如梭!我们在思考问题,感叹人生时,时间都在一分一秒的过去,哎呀!我们的时间一直都在变化呀!那么我们能不能把时间作为参数传递给srand呢?答案当然是可以的!

 我们再打开网站https://cplusplus.com查询一下time函数:

什么是时间戳?见下图:

  这时候我们再重新整合生成随机数的代码:

#include <stdio.h>
#include <stdlib.h>//函数rand的头文件为stdlib.h
#include <time.h>//函数time的头文件为time.h
int main()
{
  int input = 1;
  srand((unsigned)time(NULL)); //srand函数所需参数是unsigned int(无符号整型)类型
  //time函数的返回类型为time_t类型,其实质也是整型;
  //所以time函数的返回值自然而然可以用于srand函数的参数;
  //在上图中我们知道time函数不使用参数仍可以返回我们想要的值。
  //故time函数的参数我们用NULL(空指针),NULL以后会再提到,此处不再深究。
    while (input)                      
  {
    scanf("%d", &input);
    int random_num = rand() % 100 + 1;//任意数模100,余数为0~99,再加1,余数为1~100//
    printf("%d\n", random_num);
  }
  return 0;
}

以上才是正确生成随机数的方法。

生成随机数的问题我们解决了,接着玩游戏,我猜数字一下子猜不对,程序总要给我反馈帮助我猜出正确答案吧,所以游戏主体部分我们可以这样写:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
  int input = 1;
  int random_num = rand() % 100 + 1;
  //注意要把此等式放在循环外部,否则我们猜一次随机数就会变一次,
  //永远无法根据程序的反馈信息猜出正确答案!
  srand((unsigned)time(NULL)); 
  printf("请输入你猜的数字:\n");
  while (1)
  {
    scanf("%d", &input);
    if (input > random_num)
    {
      printf("猜大了,请再输入一次:\n");
    }
    else if (input < random_num)
    {
      printf("猜小了,请再输入一次:\n");
    }
    else
    {
      printf("恭喜你,猜对了!\n");
      break;
    }
  }
  return 0;
}

结果展示:

2.开始菜单

  一个稍微上档次一些的游戏当然要有开始菜单吧,想玩就进入游戏,不想玩就直接退出。

 我们就可以这样想:想玩你就输入1,程序就继续进行;不想玩你就输入0,直接退出游戏。

所以开始菜单代码我们想这样展示:

    printf("这是一个猜数字游戏,数字范围是1~100\n");
  printf("******如果你想玩,请输入数字1******\n");
  printf("如果你不想玩,请输入数字0,退出游戏\n");

接下来玩家的选择代码我们就可以用switch语句来写:

    int input = 0;
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    printf("游戏开始,请输入数字:\n");
  case 0:
    printf("退出游戏\n");
  default:
    printf("选择错误,请重新选择:\n");
  }

可是我们玩完一把后还想接着玩,怎么办呢?这时就可以在此基础上加上循环语句,观察以上代码,显然用do...while循环语句最合适,就可以接着这样写:

    int input = 0;
  do
    {
     scanf("%d", &input);
     switch (input)
     {
      case 1:
       printf("游戏开始,请输入数字:\n");
       break;
      case 0:
       printf("退出游戏\n");
       break;
      default:
       printf("选择错误,请重新选择:\n");
       break;
     }            
  } while (input);
  //当输入input≠0时,结果为真,打印完对应语句继续进入循环,程序继续运行;
  //当输入input=0时,结果为假,打印完“退出游戏”直接退出循环,程序终止运行;
    //开始菜单那里为什么用1和0,最重要的用处也体现在这里了

自定义函数

上面提到了库函数的查询,那么什么是自定义函数呢?

顾名思义,自定义函数当然是我们自己来设计的函数,自定义函数和库函数一样,有函数名,返回值类型和函数参数。

当我们写一个程序需要频繁的使用一个功能,或者为了实现一个功能需要写的代码量太多了,我们不希望主函数中的代码看起来繁琐杂乱无章,这时候我们完全可以把这段代码分装成函数,每次用到这个功能时只需调用函数即可。

比如以上的生成随机数和开始菜单我们就可以分装成game函数和menu函数:

完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
  printf("这是一个猜数字游戏,数字范围是1~100\n");
  printf("******如果你想玩,请输入数字1******\n");
  printf("如果你不想玩,请输入数字0,退出游戏\n");
}
void game()
{
  int random_num = rand() % 100 + 1;
  int input = 0;
  while (1)
  {
    scanf("%d", &input);
    if (input > random_num)
    {
      printf("猜大了,请再输入一次:\n");
    }
    else if (input < random_num)
    {
      printf("猜小了,请再输入一次:\n");
    }
    else
    {
      printf("恭喜你,猜对了!\n");
      break;
    }
  }
}
int main()
{
  int input = 0;
  srand((unsigned)time(NULL));
  //把此句写在主函数里是为了一次程序运行只调用一次time函数,
  //无需一直给srand传参
  do
  {
    menu();//函数的调用:调用menu函数。
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      printf("游戏开始,请输入数字:\n");
      game();//调用game函数。
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("选择错误,请重新选择:\n");
      break;
    }
  } while (input);
  return 0;
}

最后

函数的知识还有很多,比如函数的递归与迭代,传值调用和传址调用,本文中的猜数字游戏没有用到,先不提。后续再总结。

相关文章
|
11天前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
428 0
|
3月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
243 15
|
9月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
379 23
|
8月前
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
196 1
一文彻底搞清楚C语言的函数
|
9月前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
311 15
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
|
9月前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
152 24
|
9月前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
372 16
|
9月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
201 3
|
9月前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
175 2
|
9月前
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
147 1