分支和循环(二)
do while循环
格式: do{
循环语句;}
while(表达式);
特点:循环至少循环一次
例如,我们使用do while循环打印1-10
#include<stdio.h>
int main()
{
int i=1;
do{
printf(" %d ",i);
i++;
}
while(i<=10);
return 0;
}
注意:while()后记得打分号
与while循环相同,do while循环加continue之后也有可能出现死循环,原因是continue会跳过循环的调整部分
一些实例
求n的阶乘
#include<stdio.h>
int main(){
int factorial=1; //定义一个表示乘积的变量
int n=0;
scanf("%d",&n);
for(i=1;i<=n;i++){
factorial=factorial*i;
}
printf("%d",factorial);
return 0;
}
求1!+2!+3!
思路:刚刚我们求解了任何一个数n的阶乘,现在我们只需再嵌套一个循环,让n从1变到10,再求和即可
#include<stdio.h>
int main(){
int i=0;
int factorial=1;
int sum=0;
for(int n=1;n<=3;n++){
for(i=1;i<=n;i++)
{
factorial=factorial*i;
}
sum=sum+factorial;
}
printf("%d",sum);
return 0;
}
结果如下:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mOktRalA-1662121712424)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220830195455181.png)]
然而实际答案却是:1+2+6=9,为什么错误了呢。原因是我们每次循环使用的factorial没有重置导致下一次使用时factorial用的是上次计算保留的值,而每次计算时我们应该将factorial重置为1,改进为:
#include<stdio.h>
int main(){
int i=0;
int factorial=1;
int sum=0;
for(int n=1;n<=3;n++){
factorial=1; //这里使每次重新计算一个数的阶乘时,factorial从1开始
for(i=1;i<=n;i++)
{
factorial=factorial*i;
}
sum=sum+factorial;
}
printf("%d",sum);
return 0;
}
结果如下:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v0v1jG1w-1662121712425)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220830200336304.png)]
到这里,我发现这样算会嵌套两个循环,极大的增加了程序的时间复杂度,因此我们不妨想想求阶乘的另一种思路:递归的思想,因为n!=(n-1)!*n,我们求出了上一个数的阶乘,就只需在此基础上乘一个数即可,如下:
#include<stdio.h>
int main(){
int factorial=1;
int sum=0;
for(int n=1;n<=3;n++){
factorial=factorial*n; //一层for循环提高了程序的效率
sum=sum+factorial;
}
printf("%d",sum);
return 0;
}
在一个有序的数组中查找某个数字n
在数字中:1 2 3 4 5 6 7 8 9 10中找到7
思路一:存放于数组中遍历 缺点:没有用上有序的条件,这样做对于无序数组同样可以
思路二:二分查找/折半查找
左右元素下标------>中间元素下标(若遇到偶数个元素,取整即可)
#include<stdio.h>
int main(){
int arr[]={1,2,3,4,5,6,7,8,9,10};
int left=0;
int sz=sizeof(arr)/sizeof(arr[0]); //求数组的元素个数
int right=sz-1; //left,right代表的是数组元素的下标
int key=7;
while (left<=right) //注意循环条件
{
int mid=(left+right)/2; //mid要放在循环体内部,时刻随着left和right的改变值
if(arr[mid]>key){
right=mid-1;
}
else if(arr[mid]<key){
left=mid+1;
}
else{
printf("找到了,下标是:%d\n",mid);
break;
}
}
if(left>right){
printf("not found\n");
}
return 0;
}
演示多个字符从两端移动,向中间汇聚
例如:welcome !!!
###########
w#########!
we#######!!
…
welcome !!!
思路:welcome !!! 左右分别保存下标,将#(arr2)与字符(arr1)逐一替换
###########
| |
left right
#include<stdio.h>
#include<string.h>
#include<windows.h> //Sleep函数头文件
int main(){
char arr1[]={"welcome!!!"};
char arr2[]={"##########"};
int left=0;
int right=strlen(arr2)-1; //最后一个元素下标是strlen长度-1
while (left<=right)
{
arr2[left]=arr1[left];
arr2[right]=arr1[right];
printf("%s\n",arr2);
Sleep(100); //Sleep睡眠函数(单位是ms),每步停100ms,方便看出打印过程
left++;
right--;
}
return 0;
}
输出结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vn80JgYE-1662121712426)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220830213827033.png)]
模拟用户登录,并且最多登录三次
难点:判断密码正确性 两个字符串比较,不能用==来比较,应该使用函数**strcmp()**来比较两字符串是否相同
比较两个字符串,不是比较字符串的长度,而是比较对应位置的ASCII码值
//假设正确密码是:mwztwrx
#include<stdio.h>
#include<string.h> //使用strcmp函数头文件
int main(){
int i=0;
char password[20]={0}; //用数组保存密码
for(i=0;i<3;i++)
{
printf("请输入密码:\n");
scanf("%s",password);
if (strcmp(password,"mwztwrx")==0) //判断密码正误(判断字符串是否相等)
{
printf("登录成功");
break; //当登录成功时跳出循环,用再次叫用户输入密码了
}
else
{
printf("密码错误,请重新输入");
}
}
if(i==3){
printf("三次密码错误,即将退出程序");
}
return 0;
}
注意:strcmp()函数返回值有三种:
字符串1>字符串2 返回值大于0
字符串1<字符串2 返回值小于0
字符串1=字符串2 返回值等于0
猜数字游戏的实现
规则:电脑随机生成一个1-100的数字------>猜数字------>如果猜小了告知猜小了,如果猜大了告知猜大了,猜对了就告知猜对了
step1 进入界面
void menu()
{
printf("*************************************\n");
printf("****************1.play***************\n");
printf("****************0.exit***************\n");
printf("*************************************\n");
}
step2 主体搭建
对于用户输入的1/0(是/否)来进入不同的情况:用switch-case语句作为整个函数的主体(也是main函数内容)
do{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) //根据用户选择是否进入游戏
{
case 1:
game(); //创建game函数作为游戏内容
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input); //根据用户输入来执行下一步内容
step3 生成随机数
rand函数可以生成随机数,随机数的范围在0~RAND_MAX(32767)之间
在使用rand函数之前,需要调用srand函数,设置随机数的生成起点
srand函数:void srand (unsigned int seed);需要传入一个整数
//生成随机数
srand();
int ret=rand();
printf("%d",ret);
当我们在调用srand时,当srand的值确定后,生产的随机数就确定不变了,这一点也不随机。我们知道,一个变化的srand值可以对应不同的随机数值,而在电脑中,时间就是那个一直在变化的值。对于每个变化的时间,我们都有唯一的数字可以表示它,这个数字叫做时间戳,此时就要运用到time函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3FjjlSnn-1662121712427)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220831110341595.png)]
time函数格式:time_t time(time_t* timer);
|
time函数的参数
一般的,我们在使用time函数时,只需要它的返回值,不需要参数,而srand函数需要传入的数据类型是unsigned in,因此这里我们还需要进行一步强制类型转换,修改后如下:
//设置随机数生成器
srand(unsigned int)time(NULL); //强制类型转换
srand函数(生成随机数的起点)只需调用一次,在需要生成随机数的地方直接使用rand即可
按照题目要求,我们需要限定生成随机数的范围(1100):**将生成的随机数模100,那么生成的余数就在099之间,我们再在此基础上加一,就可以得到1~100的随机数了。整个生成随机数完整程序如下:
#include<stdio.h>
#include<stdlib.h> //使用srand函数的头文件
#include<time.h> //使用time函数的头文件
int main(){
srand((unsigned int)time(NULL)); //函数格式:srand(xx)注意括号
int ret=rand();
int final=(ret%100)+1;
printf(" %d ",final); //这里我们方便检测结果打印出随机数,实际上不打印
return 0;
}
这样就生成了一个100以内的随机数了:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kx8nsrZ6-1662121712427)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220831113031602.png)]
step4 猜数字
这里的思路很简单,即读取用户输入与生产的随机数final作大小的比较,而用户可以有多次机会,因此这里可以使用循环,当用户猜对后循环停止
//猜数字
while(1){
int guess=0;
printf("请猜数字:\n");
scanf("%d",&guess);
if(guess<final){
printf("猜小了\n");
}
else if(guess>final){
printf("猜大了\n");
}
else{
printf("猜对了\n");
break; //猜对了循环停止,否则循环会一直进行下去
}
}
step5 完整程序
#include<stdio.h>
#include<stdlib.h> //使用srand函数的头文件
#include<time.h>
void menu()
{
printf("*************************************\n");
printf("****************1.play***************\n");
printf("****************0.exit***************\n");
printf("*************************************\n");
}
void game()
{
srand((unsigned int)time(NULL)); //函数格式:srand(xx)注意括号
int ret=rand();
int final=(ret%100)+1; //取模结果有可能相同
int guess=0;
while (1)
{
printf("请猜数字:\n");
scanf("%d",&guess);
if(guess<final){
printf("猜小了\n");
}
else if(guess>final){
printf("猜大了\n");
}
else{
printf("猜对了\n");
break; //猜对了循环停止,否则循环会一直进行下去
}
}
}
int main(){
int input;
do{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) //根据用户选择是否进入游戏
{
case 1:
game(); //创建game函数作为游戏内容
break;
case 0:
printf("退出游戏\n");
break;
default: //对于其它值
printf("选择错误,重新选择!\n");
break;
}
} while (input); //根据用户输入来执行下一步内容
return 0;
}
运行结果如下:
goto语句
goto语句是低级语言的表征。它很灵活,灵活到没有任何拘束,在函数体内直来直往。goto语句允许把控制无条件转移到同一函数内的被标记的语句。
例如下面这段程序:
#include<stdio.h>
int main(){
flag:
printf("hello sir");
goto flag;
return 0;
}
运行结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5OlCo2B9-1662121712428)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220831143907602.png)]
可以看到,再第一个打印输出后goto语句跳到了flag的位置,继续打印输出然后形成了死循环
不太建议使用goto语句,但不代表goto语句一无是处
goto语句的适用场景:多重循环的嵌套
关机程序
设计一个在60秒后自动关机的程序,当用户输入stop后取消关机
关机命令: shutdown -s -t 60 代表电脑在60秒后执行关机
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
system("shutdown -s -t 60");
again:
printf("您的电脑将在一分钟后关机,如果输入stop,就取消关机");
char input[20] = {0};
scanf("%s", input);
if(strcmp(input, "stop") == 0){
system("shutdown -a");
printf("关机已取消");
}
else{
goto again;
}
return 0;
}
关机程序
设计一个在60秒后自动关机的程序,当用户输入stop后取消关机
关机命令: shutdown -s -t 60 代表电脑在60秒后执行关机
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
system("shutdown -s -t 60");
again:
printf("您的电脑将在一分钟后关机,如果输入stop,就取消关机");
char input[20] = {0};
scanf("%s", input);
if(strcmp(input, "stop") == 0){
system("shutdown -a");
printf("关机已取消");
}
else{
goto again;
}
return 0;
}