【C语言步行梯】循环语句for、while、do..while、goto详谈

在这里插入图片描述

🎯每日努力一点点,技术进步看得见
🏠专栏介绍:【C语言步行梯】专栏用于介绍C语言相关内容,每篇文章将通过图片+代码片段+网络相关题目的方式编写,欢迎订阅~~


循环语句

while语句

我有一个一夜暴富的梦想,如果我只要彩票没中奖,我就一直买彩票,直到中奖为止。这就是一个典型的重复行为了。如果我们想重复执行一些语句,此时该怎么办呢?
在这里插入图片描述
C语言中给我提供了3种循环语句,包括while、for、do…while循环,在这篇博客中,将一一介绍它们。首先先让我们来看一下while循环通用格式。

while()//括号里填写重复执行的条件
{
	//被重复执行的语句
}

这段代码具体是怎么执行的呢?让我来看一下程序的执行流程图↓↓↓
在这里插入图片描述

也就是说,只要满足while循环括号内的条件,它就不断执行循环体语句,知道while括号内条件不满足为止。下面,我们来试着使用while语句实现在屏幕上打印1到100。

#include <stdio.h>

int main()
{
	int i = 1;
	while(i <= 100)
	{
		printf("%d ". i);
		i++;
	}
	printf("\n");
	return 0;
}

break与continue

下面,我们再来谈谈一谈break。首先我们来看一段代码↓↓↓

#include <stdio.h>

int main()
{
	int i = 10;
	while(i >= 0)
	{
		if(i == 5)
			break;
		printf("%d ", i);
		i--;
	}
	printf("\n");
	return 0;
}

我们将这段代码丢给Visual Studio跑一下,它给出的结果是10 9 8 7 6。5到0这几个数字都不再打印了,为什么呢?

当循环体中执行到break语句时,将跳出整个循环。上面的代码中,i == 5这个条件满足时,程序将退出整个while循环,因此5到0之后的数字不再打印。

总结:break在while中的作用
在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。 所以:while中的break是用于永久终止循环的。

下面我们再看一段代码↓↓↓

#include <stdio.h>

int main()
{
	int i = 10;
	while(i >= 0)
	{
		i--;
		if(i == 5)
			continue;//Attention!!
		printf("%d ", i);
	}
	printf("\n");
	return 0;
}

这段代码和上一个没有多大变化,只是将break换成了continue。它的执行结果如下:9 8 7 6 4 3 2 1 0(没有5)。在while循环体中if语句满足条件时,将会执行continue语句。一旦执行continue语句,循环体中余下的语句将不再执行,程序将返回到while循环的判断条件处,再重新向下执行。

总结:continue在while中的作用
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。

学完while、break和continue了,那下面就让我们来小试牛刀吧( ̄︶ ̄)↗ 
在这里插入图片描述
🐂test1:看一下这段代码在做什么

#include <stdio.h>
int main()
{
	char ch = 0;
	while((ch = getchar()) != EOF)
	{
		putchar(ch);
	}
	return 0;
}

★ps:getchar用于接收用户输入的字符,每次读入一个字符;若读入失败则返回EOF。putchar用于在屏幕上打印一个字符。

揭晓答案的时刻:这段代码执行时,用户输入什么,程序就会打印什么。

🐂test2:再看一下这段代码在做什么

#include <stdio.h>
int main()
{
	char ch = 0;
	while((ch = getchar()) != EOF)
	{
		if(ch < '0' || ch > '9')
			continue;
		putchar(ch);
	}
	return 0;
}

★ps:字符在C语言中,存储的是它的ASCII码。例如:字符’0’的ASCII码的数值48,字符’9’的ASCII码的数值是57。
在这里插入图片描述
揭晓答案的时刻:ch < '0' || ch > '9'用于判断ch不是0到9这10个字符的情况,如果不是数字,则continue,继续执行循环体的判断条件。如果是数字,则不会执行continue,而是打印出来。所以,这段代码实现:用户输入数字则打印,输入其他字符不打印。

for语句

既然我们已经有了while循环语句了,那为什么我们还要学习for循环呢?那我们就得先来看看for循环的语法了↓↓↓

for(表达式1; 表达式2; 表达式3)
{
	//循环语句
}

表达式1为初始化部分,用于初始化循环变量的。表达式2为条件判断部分,用于判断
循环时候终止。表达式3为调整部分,用于循环条件的调整。

我们实现使用for循环打印1到100试试看↓↓↓

#include <stdio.h>

int main()
{
	for(int i = 1; i <= 100; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	return 0;
}

通过这段代码我们可以来分析一下for循环的执行顺序:首先它会执行表达式1,即int i = 1,且表达式1只执行1次。依次重复执行表达式2、表达式3、表达式4,知道表达式2的判断条件不再满足。

在这里插入图片描述
在这里插入图片描述
下面我们来对比一下while和for循环↓↓↓

#include <stdio.h>
int main()
{
	int i = 0;
	while(i <= 10)
	{
		printf("jammingpro\n");
		//这里可能还要很多很多代码
		i++;//导致调整条件和其他部分偏离较远
	}
	
	for(int j = 0; j <= 10; j++)
	{
		printf("xiaoming\n");
	}
	return 0;
}

可以发现在while循环中依然存在循环的三个必须条件(初始化,循环判断条件,调整条件),但是由于风格的问题使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。所以,for循环的风格更胜一筹。 for循环使用的频率也最高。

学习完for循环,我们也要小测一下( ̄︶ ̄)↗

( ఠൠఠ )ノ测试1:下面代码将输出什么?

#include <stdio.h>
int main()
{
	for(int i = 0; i <= 10; i++)
	{
		if(i == 5)
			continue;
		if(i == 8)
			break;
		printf("%d ", i);
	}
	printf("\n");
	return 0;
}

揭晓答案:0 1 2 3 4 6 7。当i==5时,将不会执行循环体的后序语句,将执行表达式i++i<=10,再进入循环体。当i==8时,执行了break语句后,将跳出整个for循环。

( ఠൠఠ )ノ测试2:下面代码将会怎么样

#include <stdio.h>
int main()
{
	for(;;)
	{
		printf("running......\n");
	}
	return 0;
}

揭晓答案:这段代码将无限次打印"running…"。当for循环的判断条件不写时,则循环条件永远为真,会一直执行循环体。

( ఠൠఠ )ノ测试3:下面代码将输出什么?

#include <stdio.h>

int main()
{
	int m = 0;
	int n = 0;
	for(m = 1, n = 2; m <= 2 && n <= 2; m++, n++)
	{
		printf("hahaha!!\n");
	}
	return 0;
}

揭晓答案:打印一行hahaha!!。for循环先执行表达式1,即m = 1, n = 2;再执行表达式2,即m <= 2 && n <= 2,因为表达式成立,所以进入循环体,打印"hahaha!!";再执行表达式3,即m++, n++,此时m变为2,n变为3;最后执行表达式2时,条件不再满足,故退出循环。

( ఠൠఠ )ノ测试4:下面代码的循环,将循环多少次?

#include <stdio.h>

int main()
{
	for(int k = 0; k = 8; k++)
	{
		printf("running......\n");
	}
	return 0;
}

揭晓答案:将会无限次循环。k = 8是一条赋值语句,返回值等于k被赋值的结果,也就是8。因为8不是0,判断条件恒为真,故循环不会停止。

do…while语句

do…while语句和while、for语句的区别是:do…while语句都会先执行1次循环体,再判断循环条件是否成立。
在这里插入图片描述
以下面代码为例,虽然循环条件不成立,但还是会执行一次循环体,打印一行“good offer”。↓↓↓

#include <stdio.h>

int main()
{
	int i = -1;
	do
	{
		printf("good offer\n");
	}while(i > 0);
	return 0;
}

所以,我们可以总结出do…while语句的特点:循环至少执行一次,使用的场景有限,所以不是经常使用。

goto语句

C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。
从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。
但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次跳出两层或多层循环。
这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。

下面是使用goto语句的一个例子:

#include <stdio.h>

int main()
{
	for(int i = 0; i < 100; i++)
	{
		for(int j = 0; j < 100; j++)
		{
			for(int k = 0; k < 100; k++)
			{
				//执行的语句
				goto endcir;
			}
		}
	}
endcir:
	printf("退出循环");
}

上面代码中,当执行到goto endcir语句时,程序将自动跳转到endcir所在行,再继续向下执行。

我们也可以使用goto语句实现循环,下面是一个关机程序,当用户在60秒内输入"Jammingpro"才能取消关机。

#include <stdio.h>
#include <stdlib.h>

int main()
{
	char ch[100] = {0};
	system("shutdown -s -t 60");
again:
	printf("请输入Jammingpro,否则程序将在启动后60秒后关机>");
	scanf("%s", ch);
	if(strcmp("Jammingpro", ch) == 0)
	{
		printf("程序终止\n");
	}
	else
	{
		printf("输入有误\n");
		goto again;
	}
	return 0;
}

循环应用案例

猜数字游戏

需求是这样的:程序生成1到100的随机数,用户输入数字进行猜测,如果猜大了,则提示用户猜大了;如果猜小了,则提示用户猜小了;如果猜对了,则提示用户猜对了,并询问是否再来一轮。

首先,我们可以先实现一个菜单函数

void menu()
{
	printf("***************************************************\n");
	printf("**************** 1.play     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;
}

最后就是要实现,猜数字了。
★ps:rand()函数位于stdlib库中,用于生成随机数。它可以生成0到32767的随机数。如果我们要生成1到100,我们可以使用rand()%100,则它会生成0到99;rand()%100+1,就可以生成1到100的随机数了。

void game()
{
	int guess = rand() % 100 + 1;
	int input = 0;
	while(1)
	{
		printf("请输入你的猜测>");
		scanf("%d", &input);
		if(input > guess)
		{
			printf("猜大了\n");
		}
		else if(input < guess)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("恭喜你猜对了\n");
			break;
		}
	}
}

但是,rand()每次生成的随机数都是一样,每次生成的随机数都是42、68、35…。应该怎么解决呢?我们需要在main函数中添加srand((unsigned int)time(NULL));,就可以实现真正产生随机数了。

★ps:rand()函数通过自己的一套数学公式,借助随机数种子(随机数种子就是一个数值)计算出一个随机数。只有随机数种子不同,才会产生不同的随机数。我们可以通过给它传入时间,这样随机数的数值就不会重复了。(unsigned int)time(NULL)就表示时间,这个时间是从1970年1月1日0时到当前经过的秒数。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void game()
{
	int guess = rand() % 100 + 1;
	int input = 0;
	while(1)
	{
		printf("请输入你的猜测>");
		scanf("%d", &input);
		if(input > guess)
		{
			printf("猜大了\n");
		}
		else if(input < guess)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("恭喜你猜对了\n");
			break;
		}
	}
}

void menu()
{
	printf("***************************************************\n");
	printf("**************** 1.play     0.exit ****************\n");
	printf("***************************************************\n");
}

int main()
{
	srand((unsigned int)time(NULL));
	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;
}

折半查找

从上面的猜数字中,我们猜数字时总会选择从中间开始猜,先猜50,如果猜小了,我们会猜75,依次类推…

当我们面对一个有序的数组时,我们也可以采用这种思想来查找一个数值。下面,我是用一个1到10的有序数组,演示如何查找数字7。
在这里插入图片描述
其中,我们定义一个left = 0,right = len - 1。因为数组有序,则left所在数值是最小值,right所在位置为最大值。通过mid=(left + right) / 2,计算出中间数值,如果该数值大于待查找数值,则待查找数值位于mid所在位置的左侧;如果该数值小于待查找数值,则待查找数值位于mid所在位置的右侧。当right<left时,说明待查找数值不存在。

下面我们来看一下实现代码↓↓↓

#include <stdio.h>

int binarySearch(int arr[], int len, int k)
{
	int left = 0;
	int right = len - 1;
	int mid = 0;

	while(left <= right)
	{
		mid = (left + right) / 2;
		if(arr[mid] < k)
		{
			left = mid + 1;
		}
		else if(arr[mid] > k)
		{
			right = mid - 1;
		}
		else
		{
			return mid;//找到了,返回下标
		}
	}
	return -1;//没有找到
}

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	int len = sizeof(arr) / sizeof(arr[0]);
	int index = binarySearch(arr, len, 7);
	if(index != -1)
	{
		printf("找到了!7位于下标%d\n", index);
	}
	else
	{
		printf("没找到\n");
	}
	return 0;
}

🚩这篇文章结束了~~
如果文章中出现了错误,欢迎私信或留言。(๑•̀ㅂ•́)و✧
有任何疑问请评论或私信哦~~o( ̄▽ ̄)ブ

  • 26
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值