1.计算n的阶乘
思路:利用循环得到数字,在对其进行累乘。
#include<stdio.h> int main() { int n = 0; scanf("%d", &n); int i = 0; int ret = 1;//不能为0 for(i = 1; i<=n; i++) { ret*=i; } printf("%d\n", i); }
2.计算1-10的阶乘和
思路1:两层循环,一个控制阶乘另一个控制阶乘和,但是在每一次计算阶乘前需要把ret重新初始化为1,因为每次循环后ret的值是被改变的。
int main() { int i = 0; int n = 1; int ret = 1; int sum = 0; while (n <= 10) { ret = 1;//重新赋值为1 for (i = 1; i <= n; i++) { ret *= i;//ret的值总被改变 } sum += ret; n++; } printf("%d\n", sum); }
优化:每个数的阶乘无非是前一个数的阶乘×这个数,对此进行优化。原先的循环次数是100次,进行优化后循环次数仅为10次。
#include<stdio.h> int main() { int i = 0; int n = 1; int ret = 1; int sum = 0; while (n <= 10) { ret *= n; sum += ret; n++; } printf("%d\n", sum); }
3.有序数组中查找具体的某个数字
思路:二分查找
我们先了解一下二分查找。例如当我们对一件商品进行估价时,往往会对其价格的区间进行折半猜测,例如商家告诉你这件商品价格区间是1-100,我们绝不会从1-100依次猜测,通常是从50,也就是区间的中点猜起,再通过商家的范围进行不断折半猜测,这就是二分查找的基本思路。
其流程大约表现为这种形式:
1.第一次查找
区间:left = 0 right = 9
中间元素下标mid = ( 0 + 9 ) / 2 = 4
mid < 6(7的下标) 说明要查找的元素比5要大,查找区间在5的右边
左下标:left -> mid + 1 = 5
更改查找范围
2.第二次查找
区间:left = 5 right = 9
中间元素下标mid = ( 5 + 9 ) / 2 = 7
mid > 6(7的下标) 说明要超找的元素比8要小,查找区间在8的左边
右下标:right -> mid - 1 = 6
更改查找范围
3.第三次查找
区间:left = 5 right = 6
中间元素下标mid = ( 5 + 6 )/ 2 = 5
mid < 6(7的下标) 说明要查找的元素比7要小,查找区间在6的右边
左下标:left-> mid + 1 = 6
更改查找范围
4.第四次查找
区间:left = 6 right = 6
中间元素下标mid = ( 6 + 6 ) / 2 = 6
mid = 6(7的下标)
mid所对应的元素和要查找的元素相等,为7,故元素找到
查找完毕
整个查找过程一共四次,相比于遍历所有元素的10次,二分查找显得更具有效率。
但是它仍然存在缺点,就是只能用与有序数组的查找。
根据题目,实现代码:
#include<stdio.h> int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int sz = sizeof(arr) / sizeof(arr[0]); int k = 7; int left = 0;//左下标 int right = sz - 1;//右下标 while (left <= right)//注意等于号 { int mid = (left + right) / 2;//中间元素下标 if (arr[mid] < k) { left = mid + 1; } else if (arr[mid] > k) { right = mid - 1; } else { printf("找到了,下标是%d\n", mid); break; } } //注意break,避免低级错误 if (left > right) printf("找不到\n"); return 0; }
注意点
:
- 起始left,right下标要写正确
- while循环的判断条件
- 中间元素下标要放在循环中,要计算多次
- 循环中有break,不能盲目打印结果
计算平均值的优化
:
int mid = left + (right - left) / 2;
4. 编写代码,演示多个字符从两端移动,向中间汇聚
题目大意
: hello-0w0-anduin!
例如上方的字符串,要求从全被#覆盖的形式,慢慢向中间汇聚显示整个字符串
#################
h###############!
he#############n!
…
hello-0w0-anduin!
思路:将两个字符串分别存储起来,使用while循环来进行字符串汇聚的操作,每次都把最左边和最右边的字符放到全是#的字符串中,直到汇聚完成。
#include<stdio.h> #include<string.h> int main() { char str1[] = "hello-0w0-anduin!"; char str2[] = "#################"; int len = strlen(str1); int left = 0; int right = len - 1; while(left <= right) { str2[left] = str1[left]; str2[right] = str1[right]; printf("%s\n",str2); left++; right--; } return 0; }
5. 模拟用户登录,输入限制三次
思路:通过strcmp进行字符串比较,判断密码是否正确,正确提示输入正确,若三次均错误则提示并退出程序。
本题密码定义为:“exploreranduin”
#include<stdio.h> #include<string.h> int main() { int i = 0; char password[50] = { 0 }; for(i = 0; i < 3; i++) { printf("请输入密码:>"); scanf("%s", password); if(strcmp(password,"exploreranduin")==0) { printf("输入正确!\n"); break; } else { printf("密码错误,请重新输入!\n"); } } //正确 or 错误 if(i==3) { printf("三次密码均错误,退出程序!\n"); } return 0; }
6. 猜数字小游戏
题目概述
:
- 电脑随机生成一个数字(1~100);
- 玩家猜数字,玩家猜小了,就告知猜小了;玩家猜大了,就告知猜大了,知道猜对为止;
- 游戏可以一直玩。
思路:
- 布置菜单
- 随机数的设置
- 游戏过程
布置菜单
函数形式让用户选择1/0,并在main函数中设置对应的选项,根据题意可以发现这个游戏至少进行一次,使用do…while循环来实现。
表现形式:
#include<stdio.h> //菜单函数 void menu() { printf("**********************************\n"); printf("*********** 1.play ***************\n"); printf("*********** 0.exit ***************\n"); printf("**********************************\n"); } int main() { int input = 0; //选择输入 do { menu();//调用菜单界面 printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: { game();//未设置,仅有进入游戏的意思 break; } case 0: { printf("退出游戏\n"); break; } default: printf("无选项,请重新输入!\n"); break; } } while (input); return 0; }
随机数的设置
所需工具 : rand
、srand
、时间戳
、time
rand
- 随机数的生成
转到定义观察RAND_MAX的值:32767
rand
返回值范围:0~32767
定义区域 - game函数内
表现形式:
#include<stdlib.h> void game() { int ret = rand(); printf("%d\n", ret); }
结合菜单部分代码并运行查看效果:
运行2次(由于结果相同,只贴第一次结果):
问题:仅仅用rand函数每次运行结果都是相同的,当每次结果相同,玩家找到规律后,这个游戏的意义就不存在了,那么该如何解决这个问题呢?
观察一下rand函数的一段描述:
表现形式:
#include<stdlib.h> void game() { srand(100); //srand(200); int ret = rand(); printf("%d\n",ret); }
当srand所接收的数据不同时,所生成的随机数也会发生改变,在同一段代码内,由于每次传的数据都相同,所以数据也想同
结合菜单部分代码运行查看效果:
srand(100)
:
srand(200)
:
srand需要接收一个无符号整型才能返回一个随机数,但我们的初衷是它自动生成,并且在游戏过程结束后,每次生成的随机数不同,为了达到效果,我们需要一个随时变化的随机值。
我们知道,时间是每时每刻发生变化的,那么可不可以用时间来充当这个随机值呢,答案是可以的,这个随机值的名字叫做时间戳.
时间戳 - 向srand提供随时变化的随机值
概念:当前时间和计算机起始时间(1970年1月1日0时0分0秒)之间的差值
time - 接收时间戳
表现形式:
观察返回值time_t
的类型:
注意点:
time返回的就是整数,而srand所需的值是无符号整数,这时只需要强制类型转化一下就可以了。由于srand不需要频繁调用,所以我们只需要将其在main函数中定义一次即可。
rand的返回值范围是0 ~ 32767,对于游戏而言,这无疑加大了难度,所以我们可以将数据约束到1 ~ 100范围内,使游戏更加人性化。而如何达到就只需要ret接收的数据%100再+1就可以了(因为任何数%100的值的范围为0~99).
结合以上两点,核心代码表现形式为:
#include<time.h> #include<stdio.h> #include<stdlib.h> void game() { int ret = rand()%100 + 1; printf("%d\n", ret); } int main() { srand((unsigned int)time(NULL)); return 0; }
结合其余代码运行结果:
到此,随机数的生成问题就解决了。
游戏过程
要点:
- 游戏有连续性,循环一直都要进行
- 多分支判断
- 猜对了要设置出口,不能猜对了一直猜
表现形式:
#include<stdio.h> #include<stdlib.h> #include<time.h> //游戏实现 void game() { int guess = 0;//输出猜测值 int ret = rand() % 100 + 1;//生成一个随机数 //猜数字 while (1) { printf("请输入数字:>"); scanf("%d", &guess); if (guess > ret) { printf("猜大了\n"); } else if (guess < ret) { printf("猜小了\n"); } else { printf("恭喜你,猜对了!\n"); break;//注意游戏结束 } }
完整游戏展示:
#include<stdio.h> #include<stdlib.h> #include<time.h> void menu() { printf("**********************************\n"); printf("*********** 1.play ***************\n"); printf("*********** 0.exit ***************\n"); printf("**********************************\n"); } void game() { int guess = 0; int ret = rand() % 100 + 1; while (1) { printf("请输入你猜测的数字:>"); scanf("%d", &guess); if (guess > ret) { printf("猜大了\n"); } else if (guess < ret) { printf("猜小了\n"); } else { printf("恭喜你,猜对了!\n"); break; } } } int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: break; default: printf("选择错误,请重新输入!\n"); break; } } while (input); return 0; }
运行结果:
7. 结语
以上就是循环练习和猜数字小游戏的全部内容,对于分支与循环这章我们到此为止了,接下来anduin会恢复正常更新速度,更多内容,敬请期待!