前言
本文接着上文,继续学习循环。
3.3 do…while()循环
3.3.1 语法
do
循环语句;
while(表达式);
3.3.2 执行流程
do…while()循环和while循环、for循环不同的是,do…while()是首先执行一次循环语句,然后执行判断语句,若判断条件为真,接着执行循环语句;否则退出循环。
3.3.3 do语句的特点
循环至少执行一次,使用的场景有限,所以不是经常使用。
int main()
{
int i = 10;
do
{
printf("%d\n", i);
}while(i<10);
return 0;
}
3.3.4 do— while循环中的break和continue
3.3.4.1 break的例子
int main()
{
int i = 1;
do
{
if (i == 5)
{
continue; //只输出1 2 3 4,后面就进入死循环了
}
printf("%d ", i);
i++;
} while (i<=10);
return 0;
}
输出结果: 1 2 3 4
程序进入死循环,还没结束
3.3.4.2 continue的例子
int main()
{
int i = 1;
do
{
if (i == 5)
{
break;
}
printf("%d ", i);//只输出1 2 3 4,后面break,循环都不执行了,
//程序结束了
i++;
} while (i <= 10);
return 0;
}
输出结果: 1 2 3 4
3.4 练习
3.4.1 计算n的阶乘
int main()
{
int ret = 1;
for (int i = 1; i <=3; i++)
{
ret = ret * i;//计算3的阶乘,输出是6
}
printf("%d", ret);
return 0;
}
输出结果,3的阶乘 3!= 6
修改程序,随意输入一个整数,求n阶乘。
int main()
{
int num = 1;
int ret = 1;
scanf("%d", &num);//输入整数
for (int i = 1; i <= num; i++)
{
ret = ret * i;//求阶乘
}
printf("%d", ret);
return 0;
}
输入3,输出6
3.4.2 输出n的阶乘求和
将各个数的阶乘求出后,再相加。代入1,2 ,3计算。
int main()
{
int n ,j,ret = 1;
int sum = 0;
for (n = 1; n <= 3; n++)//一共n个数,外部循环
{
ret = 1;
for ( j = 1; j <=n; j++)//每个数求阶乘,内部循环
{
ret = ret * j;//求阶乘
}
sum += ret;//阶乘求和
}
printf("%d", sum);
return 0;
}
上面的程序求阶乘,是每一个数字都从1开始相乘到自身,求出阶乘后再相加。可以对程序进行优化,每次相乘不要从1开始,可以将前面的结果保存起来,乘上最后一个数。例如:求3的阶乘,不用再用1x2x3,而是用2!乘以3。
int main()
{
int n = 1;
int ret = 1;
int sum = 0;
for (n = 1; n <= 3; n++)
{
ret = ret * n;
sum += ret;
}
printf("%d", sum);
return 0;
}
输出结果为9。
3.4.3 二分法查找数
二分法查找,又可以称为折半查找算法。每次查找后,下一次的查找范围就能减少一半。
比如我买了一双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜?
答案:你每次猜中间数。
int main()
{
int arr[] = {
1,2,3,4,5,6,7,8,9,10 };
int k = 7;//这是要查找的数,其下标为6
int length = sizeof(arr) / sizeof(arr[0]);//求取数组长度
int left = 0;//左下标
int right = length - 1;//右下标
int mid = 0;//中间
while (left<=right)
{
mid = left + (right-left) / 2;//改成这种较好
//mid = (left + right) / 2;
//上面的写法有个缺点,当上下标无限大时,两者之和会超出定义类型范围
if (arr[mid]>k)
{
//第一次比对,中间值超过K,则k的范围在数组的左半边
//所以缩写范围,左标为0不动,右边变成中间减1,就是中间值的左边一位
right = mid - 1;
}
else if (arr[mid] < k)
{
//若第一次比对,中间值小于K,则k的范围在数组的右半边
//所以缩小一半范围,右标为0不动,左边变成中间加1,就是中间值的右边一位
left = mid + 1;
}
else//左右相等时就是找到了那个数
{
printf("找到了,下标是: %d\n", mid);
break;
}
}
if (left>right)//左标超过右标,找不到
{
printf("找不到了\n");
}
return 0;
}
3.4.4 多个字符从两端向中间移动
分别用while循环和for循环写程序:
3.4.4.1 while循环代码
//注意这两个头文件要添加
#include<stdlib.h>//库函数
#include<Windows.h>//和win系统相关
int main()
{
char arr1[] = "welcome to bit!!!!!";
char arr2[] = "###################";
int left = 0;
int right = strlen(arr1)-1;//下标减1
printf("%s\n", arr2);
//while循环
while (left<=right)
{
Sleep(1000);//延迟函数,延长1秒时间,打印效果明显
arr2[left] = arr1[left];//字符串对应位置赋值
arr2[right] = arr1[right];
left++;//左边向中间移动
right--;//右边向中间移动
printf("%s\n", arr2);
}
return 0;
}
输出结果如下:
3.4.4.2 for循环代码
//注意这两个头文件要添加
#include<stdlib.h>//库函数
#include<Windows.h>//和win系统相关
int main()
{
char arr1[] = "welcome to bit!!!!!";
char arr2[] = "###################";
int left = 0;
int right = strlen(arr1)-1;
printf("%s\n", arr2);
//for循环
for (left=0,right=strlen(arr1)-1; left <= right; left++,right--)
{
Sleep(1000);
system("cls");//清屏,动态刷新函数
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
}
return 0;
}
使用了清屏函数,输出结果会动态显示在一行上
3.4.5 密码登录三次
判断两个字符串是否相同,比较是不能使用==,应该使用strcmp
#include<string.h>
int main()
{
char password[20] = {
0 };
int i, j = 0;
//假设正确密码为abcd
for ( i = 0; i < 3; i++)
{
printf("请输入密码: ");
scanf("%s", password);
//两个字符串的比较是不能使用==
//应该使用strcmp
//将输入密码与正确密码比较,相同则返回值为0
if (strcmp(password,"abcd")==0)
{
printf("密码正确!\n");
break;
}
else
{
printf("密码错误,请重新输入!\n");
}
}
if (i==3)
{
printf("三次密码都输入错误,退出程序!\n");
}
return 0;
}
3.4.6 猜数字游戏
游戏要求:
- 电脑随机生成一个数字(1~100)
- 玩家猜数字
玩家猜小了,就告知猜小了
玩家猜大了,就告知猜大了
直到猜对为止 - 游戏可以一直玩
#include<time.h>
#include<stdlib.h>
void menu()
{
printf("************************\n");
printf("******** 1.play ******\n");
printf("******** 0.exit ******\n");
printf("************************\n");
}
void play()
{
//1、生成随机数
int random_num = rand() % 100 + 1;//生成1-100的随机数字
//printf("%d\n",random_num);
int input = 0;
while (1)
{
printf("请输入数字: ");
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 int)time(NULL));//跟系统时间相关的真正的随机数
do
{
menu();//先输出
printf("请按菜单选则: ");//先输出
scanf("%d", &input);//根据输入判断
switch (input)
{
case 1://玩游戏
play();
break;
case 0://退出游戏
printf("退出游戏\n");
break;
default://
printf("选择错误,重新选择!\n");
break;
}
} while (input);
//输入为1,进入循环,玩游戏
// 为0退出循环
//输入其他,则依旧循环,重新输入,直到输入的是1或0为止
return 0;
}
4、goto语句
C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。
从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。
但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。
例如:一次跳出两层或多层循环。
多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。
4.1 goto语言真正适合的场景
真正的适用场景如下:
for(...)
for(...)
{
for(...)
{
if(disaster)
goto error;//返回,退出到标签出
}
}
…
error://标签
if(disaster)
// 处理错误情况
4.2 goto举例
4.2.1 goto 语句不能跨函数跳转
int main()
{
n:
printf("hehe\n");
printf("hehe\n");
printf("hehe\n");
goto n;//goto 语句不能跨函数跳转
return 0;
}
4.2.2 一个关机程序
下面是使用goto语句的一个例子,然后使用循环的实现方式替换goto语句
只要程序运行起来,电脑就在1分钟内关机,如果输入:我是猪,就取消关机。(这个关机程序大家看看就行,最好不要运行,真会关机的)
//关机程序,请大家不要尝试运行
#include <stdlib.h>
#include <string.h>
int main()
{
char input[20] = {
0};
system("shutdown -s -t 60");//system是一个库函数,是用来执行系统命令的
again:
printf("请注意,你的电脑在1分钟内关机,如果输入:我是猪,就取消关机\n");
scanf("%s", input);
//判断
if (strcmp(input, "我是猪") == 0)
{
system("shutdown -a");//取消关机
}
else
{
goto again;
}
return 0;
}
不用goto语句,用while循环也可以实现。
int main()
{
char input[20] = {
0 };
system("shutdown -s -t 60");//system是一个库函数,是用来执行系统命令的
while (1)
{
printf("请注意,你的电脑在1分钟内关机,如果输入:我是猪,就取消关机\n");
scanf("%s", input);
//判断
if (strcmp(input, "我是猪") == 0)
{
system("shutdown -a");//取消关机
break;
}
}
return 0;
}
总结
本文和上篇文章集中写了分支和循环语句的知识,按照B站的学习内容更新,这部分内容也暂时告一段落了。随着后续学习的深入,如果有进一步的体会,前面的博文也会适当做一些修改。
下篇将会更新函数相关的内容。