猜数字游戏——分支和循环语句

C语言学习之分支和循环语句


前言

最近刷题遇到了好多的选择结构和循环结构,简单记录一下使用分支和循环语句的方法。


一、概述

可以使⽤ if 、 switch 实现分⽀结构,使⽤ for 、 while 、 do while 实现循环结构。

二、分支和循环语句实例

1.分支语句

1.1 if 语句的使用

#include <stdio.h>
int main()
{
	int num = 0;
	scanf("%d", &num);
	if (num % 2 == 1)
		printf("%d 是奇数\n", num);//num是奇数,打印出结果。如果为偶数,则不执行打印语句,没有显示
	return 0;
}

输入2的执行结果:
只有printf中"\n"留下的换行
输入1的执行结果:
输入奇数的结果
特点:判断为真(非零),则执行 if 后的语句,默认 if 后只跟一条语句。若要跟多条语句,可以使用" { } "将其后要执行的语句括起来,成为一个代码块。 下方的 if 语句同理。

1.1.1 if…else语句
#include <stdio.h>
int main()
{
	int age = 0;
	scanf("%d", &age);
	if (age >= 18)
		printf("成年\n");
	else
		printf("未成年\n");
	return 0;
}

特点:首先判断 if 后的条件,条件为真(非零),执行紧挨 if 的下一条语句;为假(零),执行 else
后的语句。

1.1.2 if…else if …else( if 的嵌套)语句
#include <stdio.h>
int main()
{
	int age = 0;
	scanf("%d", &age);
	if (age < 18)
	{
		printf("少年\n");
	}
	else
	{
		if (age <= 44)
		{
			printf("青年\n");
		}
		else
		{
			if (age <= 59)
			{
				printf("中老年\n");
			}
			else
			{
				if (age <= 90)
					printf("老年\n");
				else
					printf("老寿星\n");
			}
		}
	}
	return 0;
}

等价以下代码。"{ }"的添加只是为了直观看到 if 的嵌套。 else 的匹配规则:跟上方最接近的 if 匹配。

#include <stdio.h>
int main()
{
	int age = 0;
	scanf("%d", &age);
	if (age < 18)
		printf("少年\n");
	else if (age <= 44)
		printf("青年\n");
	else if (age <= 59)
		printf("中老年\n");
	else if (age <= 90)
		printf("老年\n");
	else 
		printf("老寿星\n");
	return 0;
}

1.2 switch 语句的使用

#include <stdio.h>
int main()
{
	int day = 0;
	scanf("%d", &day);
	switch (day)
	{
		case 1:
			printf("星期一\n");
			break;
		case 2:
			printf("星期二\n");
			break;
		case 3:
			printf("星期三\n");
			break;
		case 4:
			printf("星期四\n");
			break;
		case 5:
			printf("星期五\n");
			break;
		case 6:
			printf("星期六\n");
			break;
		case 7:
			printf("星期天\n");
			break;
		default :
			printf("输入错误,请重新输入【1-7】\n");
	}
	return 0;
}

使用时要注意switch 后的 expression 必须是整型表达式,case 后的值,必须是整形常量表达式。如果case后跟一个 float 类型如:

case 1.1:    //error,编译会出现错误
printf("你好\n");

break可以直接跳出switch语句,不再执行它之后的语句。当 break 出现在 for / while /do while循环中时,会永久地终止它所在的循环,注意break一次只能跳出一层循环。如 for 循环中嵌套一个 while 循环,当 while 中出现 break 时,只是跳出了它所在的 while 循环,但外层的 for 循环还在继续。

可以将部分条件进行合并,如下方代码:

#include <stdio.h>
int main()
{
	int day = 0;
	scanf("%d", &day);
	switch (day)
	{
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
			printf("工作日\n");
			break;
		case 6:
		case 7:
			printf("休息日\n");
			break;
		default :
			printf("输入错误,请重新输入【1-7】\n");
	}
	return 0;
}

2.循环语句

2.1 for循环的使用:

#include <stdio.h>
int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
		printf("%d ", i);
	return 0;
}

先对 i 赋初值, i = 0 ,判断条件 i < 10 成立,则执行下方循环体(打印),最后更新 i 的值(加一),这就是完整的一次循环。当 i 等于10 的时候,判断条件 i < 10 不再成立,则跳出循环。
代码执行结果为:
for 循环结果

2.1.1 for循环的嵌套(九成九乘法表)
#include <stdio.h>
int main()
{
	int i = 0;
	for (i = 1; i < 10; i++)//生成第一个乘数,从 1 到 9
	{
		int j = 0;
		for (j = 1; j <= i; j++)//对于生成的每个【第一个乘数】,生成对应的第二个乘数,第二个乘数 <= 第一个乘数
		{
			printf("%d * %d = %2d  ", i, j, i * j);//注意%2d后边加了两个空格,防止每行相邻打印结果的距离太近
		}
		printf("\n");//打印完第一个乘数对应的所有乘法算式后,换行。为了效果整齐美观
	}
	return 0;
}

编写这个案例时,注意%2d用来限制输出结果的格式。因为乘法表中,乘法的结果从一位数过渡到两位数,如果不限制最小位数为2的话,打印的效果有明显的不美观之处。来看执行结果的对比吧。
使用格式限制最小输出位数%2d的执行结果:
乘法表

没有使用%2d的执行结果:(有没有看到图中圈出区域,和其它的“画风”不一致啊^ - ^)
乘法表结果2

2.2 while循环的使用:

#include <stdio.h>
int main()
{
	int i = 1;
	while (i <= 10)
	{
		printf("%d ", i);
		i = i + 1;
	}
	return 0;
}

执行结果:
结果
特点:先判断,结果为真(非零)才执行循环体。每次执行期间,都会对循环因子进行修改(否则就成为死循环),修改完成后如果while条件表达式成立,继续循环,如果不成立,循环结束。
故:while循环条件将会比循环体多执行一次。

2.3 do…while循环的使用:

#include <stdio.h>
int main()
{
	int i = 1;
	do
	{
		printf("%d ", i);
		i = i + 1;
	} while (i <= 10);

	return 0;
}

执行结果:
结果
特点:先执行一次循环体,再判断,为真(非零),继续执行循环体,否则结束循环。循环体执行次数和循环条件的判断次数相等。

3.分支和循环语句的结合使用(猜数字小游戏)

先上代码:

#include <stdio.h>//printf和scanf使用的头文件
#include <stdlib.h>//srand和rand使用的头文件
#include <time.h>//time使用的头文件
void menu()//打印菜单
{
	printf("*************************\n");
	printf("*** 1.plat     0.exit ***\n");
	printf("*************************\n");
}

//01
void game()
{
	int guess = 0;
	int count = 0;
	//随机数1-100
	int ret = rand() % 100 + 1;//使用随机数种子srand生成伪随机数
	//游戏具体过程
	while (1)
	{
		if (count >= 5)
		{
			printf("很遗憾,您的游戏机会已经用完,本次的随机数是%d\n", ret);
			break;
		}
		printf("你还有%d次机会\n", 5 - count);
		printf("请输入你的猜测数字:  ");
		scanf("%d", &guess);
		//输入值和随机数大小的比较和游戏提示
		if (guess > ret)
		{
			printf("大了\n");
			printf("\n");
			count++;
		}
		else if (guess < ret)
		{
			printf("小了\n");
			printf("\n");
			count++;
		}
		else
		{
			printf("恭喜你!猜对了,你好厉害啊^-^\n");
			break;//猜正确后直接跳出while循环
		}
	}
}

02
//void game()
//{
//	int guess = 0;
//	int count = 5;
//	//随机数1-100
//	int ret = rand() % 100 + 1;//使用随机数种子srand生成伪随机数
//	//游戏具体过程
//	while (count)
//	{
//		printf("你还有%d次机会\n", count);
//		printf("请输入你的猜测数字:  ");
//		scanf("%d", &guess);
//		if (guess > ret)
//		{
//			printf("大了\n");
//			printf("\n");
//		}
//		else if (guess < ret)
//		{
//			printf("小了\n");
//			printf("\n");
//		}
//		else
//		{
//			printf("恭喜你!猜对了,你好厉害啊\n");
//			break;//猜正确后直接跳出while循环
//		}
//		count--;
//	}
//	if (count == 0)
//		printf("很遗憾,您的游戏机会已经用完,本次的随机数是%d\n", ret);
//}

int main()
{
	srand((unsigned int)time(NULL));//随机数的种子
	int input = 0;
	do
	{
		menu();//打印菜单
		printf("请输入你的选择->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//暂时发现五次机会太少了,试了十次,就对了一次。。。
			//printf("开始游戏\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误!请重新选择\n");
		}
		printf("\n");
	} while (input);
	return 0;
}

3.1 伪随机数和 rand() 、srand() 和 time()

这里着重说明如何产生伪随机数

rand() 函数⽣成的随机数是伪随机的,它是对⼀个叫“种⼦” seed 的基准值进⾏运算⽣成的随机数,且生成随机数的默认种子是1,因此程序要获得更接近随机效果的随机数,必须让这个种子产生变化。如果直接使用 rand 生成的随机数,你会发现代码运行时,每次产生的随机数都一样(举个例子:这次程序运行,生成的前三个随机数是1,2,3,下次程序运行时生成的前三个随机数还是1,2,3),那不就对不起“随机”这两个字了吗?我们要得到每次程序运行时,都会随机出现的数值作为随机值。

C语⾔中⼜提供了⼀个函数叫 srand(),⽤来初始化随机数的⽣成器,srand的原型为:

void srand(unsigned int seed) ;

程序中在调⽤ rand 函数之前先调⽤ srand 函数,通过 srand 函数的参数seed来设置rand函数⽣成随机数的种⼦,只要种⼦在变化,每次⽣成的随机数序列也就变化起来了。

我们通过使用电脑上的时间来作为种子。来看这个函数:

函数原型: time_t time(time_t timer)

参数说明: timer=NULL时得到当前日历时间(从1970-01-01 00:00:00到现在时间的秒数),timer=时间数值时,用于设置日历时间,time_t是时能够表示时间的基本算术类型的别名。如果 timer不为空,则返回值也存储在变量 timer中。

使用时,可以将 time() 这个函数作为种子传递给 srand ,将time_t *timer设置为NULL,将当前日历时间作为一个种子,让rand调用这个种子生成对应的伪随机数。将前边生成的结果和100取余,得到0-99的随机数,但我需要1-100的随机数,所以将前边的结果加一。再来看相关的代码行:

srand((unsigned int)time(NULL));//随机数的种子

//随机数1-100
int ret = rand() % 100 + 1;//使用随机数种子srand生成伪随机数

来个游戏成功的截图,这次我运气不错,成功了,开始飘了,我好 b( ̄▽ ̄)d 厉害:
结果

上边示例的代码中可以看到游戏的具体实现子程序 game() 有两个版本01和02,这个主要是由于设置游戏次数的限制时,使用的计数方式不同(控制 while 循环的判定条件),所造成的代码也有些许不同。大家可以自行尝试不同的方式,加深理解。

最后提醒,在设计本次代码时,获得1-100随机数的代码不能放在游戏实现函数 game() 的 while 循环内。玩了一局之后,你还能玩一局,之后你玩的每一局游戏,产生的随机数都是在程序刚开始运行时设置的同一个种子产生的不同的随机数,while 循环只负责判断玩家是否猜到了随机数和给你游戏提醒,如果你将获得1-100随机数的代码放在 while 循环中,每次循环判断是否猜到随机数时,也会对随机数进行一次更新,也就是你的猜测结果每判断一次,随机数(猜测的答案)就改变一次,哈哈哈,这时拼的就是纯纯的运气了,你只要猜测一次,随机数(猜测的答案)就变一次,这还怎么玩。真是刺激【手动滑稽】!!!还有提示的信息逻辑别搞乱了,比如玩家猜测的数实际是大于既定的随机数,但你给玩家提示小了,好家伙,一身反骨,照着游戏提示,一辈子也猜不对呀!


总结

C语言中的分支和循环语句,在代码中是经常使用的结构。分支语句提供多个选择,当你达到某种要求后只能选择一个,比如一个高达模型300元,一个小飞机250元,你只有250元,那么你只能买一个小飞机,因为你只拥有购买飞机的金额,你的选择就是买飞机。循环语句是一个为了得到某个结果的重复性动作,比如我要求你蛙跳100次后才能吃饭,蛙跳就是动作,100是我规定的重复动作的次数,吃饭是一个结果,如果你只跳了1次就来问我:“我能去吃饭了吗?”,那得到的答案肯定就是不能,只有你跳够100次才能得到吃饭的奖励(结果)。任何分支和循环语句在使用前,要梳理出想要得到的结果,要实现何种功能,将实现过程拆分成可实现的一条条的语句,合理选择分支或循环语句。

  • 25
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录: 第1章 5个例子 1 1.1 开始 1 1.2 编辑、编译和运行 3 1.3 Hello Who? 6 1.4 大数字——二维切片 8 1.5 栈——自定义类型及其方法 12 1.6 americanise示例——文件、映射和闭包 18 1.7 从极坐标到笛卡儿坐标 ——并发 28 1.8 练习 33 第2章 布尔与数值类型 35 2.1 基础 35 2.2 布尔值和布尔表达式 39 2.3 数值类型 40 2.3.1 整型 42 2.3.2 浮点类型 46 2.4 例子:statistics 53 2.4.1 实现一个简单的统计函数 54 2.4.2 实现一个基本的HTTP服务器 55 2.5 练习 58 第3章 字符串 60 3.1 字面量、操作符和转义 61 3.2 比较字符串 63 3.3 字符和字符串 65 3.4 字符串索引与切片 67 3.5 使用fmt包来格式化字符串 69 3.5.1 格式化布尔值 73 3.5.2 格式化整数 74 3.5.3 格式化字符 75 3.5.4 格式化浮点数 75 3.5.5 格式化字符串和切片 76 3.5.6 为调试格式化 78 3.6 其他字符处理相关的包 80 3.6.1 strings包 81 3.6.2 strconv包 86 3.6.3 utf8包 90 3.6.4 unicode包 91 3.6.5 regexp包 92 3.7 例子:m3u2pls 101 3.8 练习 106 第4章 集合类型 108 4.1 值、指针和引用类型 108 4.2 数组和切片 115 4.2.1 索引与分割切片 119 4.2.2 遍历切片 119 4.2.3 修改切片 121 4.2.4 排序和搜索切片 125 4.3 映射 128 4.3.1 创建和填充映射 129 4.3.2 映射查询 131 4.3.3 修改映射 132 4.3.4 键序遍历映射 132 4.3.5 映射反转 133 4.4 例子 134 4.4.1 猜测分隔符 134 4.4.2 词频统计 136 4.5 练习 141 第5章 过程式编程 144 5.1 语句基础 144 5.1.1 类型转换 147 5.1.2 类型断言 148 5.2 分支 149 5.2.1 if语句 150 5.2.2 switch语句 151 5.3 for循环语句 158 5.4 通信和并发语句 160 5.5 defer、panic和recover 166 5.6 自定义函数 171 5.6.1 函数参数 172 5.6.2 init()函数和main()函数 175 5.6.3 闭包 176 5.6.4 递归函数 178 5.6.5 运行时选择函数 181 5.6.6 泛型函数 183 5.6.7 高阶函数 187 5.7 例子:缩进排序 192 5.8 练习 197 第6章 面向对象编程 199 6.1 几个关键概念 199 6.2 自定义类型 201 6.2.1 添加方法 203 6.2.2 验证类型 207 6.3 接口 209 6.4 结构体 217 6.5 例子 224 6.5.1 FuzzyBool——一个单值自定义类型 224 6.5.2 Shapes——一系列自定义类型 229 6.5.3 有序映射——一个通用的集合类型 240 6.6 练习 248 第7章 并发编程 251 7.1 关键概念 252 7.2 例子 256 7.2.1 过滤器 256 7.2.2 并发的Grep 260 7.2.3 线程安全的映射 266 7.2.4 Apache报告 271 7.2.5 查找副本 278 7.3 练习 285 第8章 文件处理 287 8.1 自定义数据文件 287 8.1.1 处理JSON文件 290 8.1.2 处理XML文件 295 8.1.3 处理纯文本文件 301 8.1.4 处理Go语言二进制文件 307 8.1.5 处理自定义的二进制文件 309 8.2 归档文件 317 8.2.1 创建zip归档文件 317 8.2.2 创建可压缩的tar包 319 8.2.3 解开zip归档文件 321 8.2.4 解开tar归档文件 322 8.3 练习 324 第9章 包 326 9.1 自定义包 326 9.1.1 创建自定义的包 327 9.1.2 导入包 333 9.2 第三方包 334 9.3 Go命令行工具简介 335 9.4 Go标准库简介 336 9.4.1 归档和压缩包 336 9.4.2 字节流和字符串相关的包 336 9.4.3 容器包 337 9.4.4 文件和操作系统相关的包 339 9.4.5 图像处理相关的包 341 9.4.6 数学处理包 341 9.4.7 其他一些包 341 9.4.8 网络包 342 9.4.9 反射包 343 9.5 练习 346
第1章 5个例子 1 1.1 开始 1 1.2 编辑、编译和运行 3 1.3 Hello Who? 6 1.4 大数字——二维切片 8 1.5 栈——自定义类型及其方法 12 1.6 americanise示例——文件、映射和闭包 18 1.7 从极坐标到笛卡儿坐标——并发 28 1.8 练习 33 第2章 布尔与数值类型 35 2.1 基础 35 2.2 布尔值和布尔表达式 39 2.3 数值类型 40 2.3.1 整型 42 2.3.2 浮点类型 46 2.4 例子:statistics 53 2.4.1 实现一个简单的统计函数 54 2.4.2 实现一个基本的HTTP服务器 55 2.5 练习 58 第3章 字符串 60 3.1 字面量、操作符和转义 61 3.2 比较字符串 63 3.3 字符和字符串 65 3.4 字符串索引与切片 67 3.5 使用fmt包来格式化字符串 69 3.5.1 格式化布尔值 73 3.5.2 格式化整数 74 3.5.3 格式化字符 75 3.5.4 格式化浮点数 75 3.5.5 格式化字符串和切片 76 3.5.6 为调试格式化 78 3.6 其他字符处理相关的包 80 3.6.1 strings包 81 3.6.2 strconv包 86 3.6.3 utf8包 90 3.6.4 unicode包 91 3.6.5 regexp包 92 3.7 例子:m3u2pls 101 3.8 练习 106 第4章 集合类型 108 4.1 值、指针和引用类型 108 4.2 数组和切片 115 4.2.1 索引与分割切片 119 4.2.2 遍历切片 119 4.2.3 修改切片 121 4.2.4 排序和搜索切片 125 4.3 映射 128 4.3.1 创建和填充映射 129 4.3.2 映射查询 131 4.3.3 修改映射 132 4.3.4 键序遍历映射 132 4.3.5 映射反转 133 4.4 例子 134 4.4.1 猜测分隔符 134 4.4.2 词频统计 136 4.5 练习 141 第5章 过程式编程 144 5.1 语句基础 144 5.1.1 类型转换 147 5.1.2 类型断言 148 5.2 分支 149 5.2.1 if语句 150 5.2.2 switch语句 151 5.3 for循环语句 158 5.4 通信和并发语句 160 5.5 defer、panic和recover 166 5.6 自定义函数 171 5.6.1 函数参数 172 5.6.2 init()函数和main()函数 175 5.6.3 闭包 176 5.6.4 递归函数 178 5.6.5 运行时选择函数 181 5.6.6 泛型函数 183 5.6.7 高阶函数 187 5.7 例子:缩进排序 192 5.8 练习 197 第6章 面向对象编程 199 6.1 几个关键概念 199 6.2 自定义类型 201 6.2.1 添加方法 203 6.2.2 验证类型 207 6.3 接口 209 6.4 结构体 217 6.5 例子 224 6.5.1 FuzzyBool——一个单值自定义类型 224 6.5.2 Shapes——一系列自定义类型 229 6.5.3 有序映射——一个通用的集合类型 240 6.6 练习 248 第7章 并发编程 251 7.1 关键概念 252 7.2 例子 256 7.2.1 过滤器 256 7.2.2 并发的Grep 260 7.2.3 线程安全的映射 266 7.2.4 Apache报告 271 7.2.5 查找副本 278 7.3 练习 285 第8章 文件处理 287 8.1 自定义数据文件 287 8.1.1 处理JSON文件 290 8.1.2 处理XML文件 295 8.1.3 处理纯文本文件 301 8.1.4 处理Go语言二进制文件 307 8.1.5 处理自定义的二进制文件 309 8.2 归档文件 317 8.2.1 创建zip归档文件 317 8.2.2 创建可压缩的tar包 319 8.2.3 解开zip归档文件 321 8.2.4 解开tar归档文件 322 8.3 练习 324 第9章 包 326 9.1 自定义包 326 9.1.1 创建自定义的包 327 9.1.2 导入包 333 9.2 第三方包 334 9.3 Go命令行工具简介 335 9.4 Go标准库简介 336 9.4.1 归档和压缩包 336 9.4.2 字节流和字符串相关的包 336 9.4.3 容器包 337 9.4.4 文件和操作系统相关的包 339 9.4.5 图像处理相关的包 341 9.4.6 数学处理包 341 9.4.7 其他一些包 341 9.4.8 网络包 342 9.4.9 反射包 343 9.5 练习 346 附录A 后记 348 附录B 软件专利的危害 350 附录C 精选书目 353

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值