C语言学习笔记之循环结构

(如有错误请指出)

所谓循环结构就是在给定条件成立时,重复执行某段程序。循环结构中,给定的条件称为循环条件,重复执行的程序叫做循环体。C语言中有for、while、do...while三种循环语句实现循环结构。

目录

一、while循环

二、for循环

三、do...while循环

四、goto语句

五、总结

六、练习


一、while循环

while语句的结构为:  while(表达式)

                                    循环体(注:循环体可以是一个语句也可以是{ }括起来的多条语句)

例如用while实现100!

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int a = 1, b = 0;
	while (a <= 100)
	{
		b += a;
		a++;

	}
	printf("100!=%d", b);
	return 0;
}

当while后面的()里面的值为0时也停止循环。

 在下面的程序里面a--和--a最后的结果相同而循环的次数不同:a--循环了101次而--a循环了100次。a--:上一轮循环结束后a=2,此时括号里面的值为2,继续循环,b加上了1,然后括号里的值变为了1,b加上了0。而在--a中上一轮结束后a=2,此时括号里面的值为1,继续循环,b加上了1,然后括号里面的值变为了0循环结束,比a--少了一个循环。

C语言学习笔记之循环结构_第1张图片

 break语句只用在Switch语句和循环语句中,在循环语句的作用是跳出循环体,去执行循环体后面的程序,和Switch语句中的作用类似。下面的程序在a=90的时候遇到break,跳出循环语句所以只循环了10次。

 continue语句只能用于循环结构,作用是结束本次循环,不再执行循环体中continue之后的语句,转而跳转到判断循环条件(也就是while()这一段程序)。

C语言学习笔记之循环结构_第2张图片

 上面的这段程序在a=10的时候执行continue语句所以跳转到while(a<=100)继续执行然后又跳转回来,陷入死循环。然而只需要改变一个语句的位置就可解除危机。我们发现陷入死循环的原因是a的值一直为10,那么我们仅需要把a++放在循环体中continue语句之前就可以解决问题。而付出的代价是:a=10这一情况被跳过。而若想在计算100!过程中跳过a=10这一情况需要这样改动:

C语言学习笔记之循环结构_第3张图片

 break语句和continue语句的区别在于:break终止整个循环体的执行,跳出循环体执行它后面的程序,不去判断循环条件;而continue终止此次循环,跳转到判断循环条件是否成立这一步。

二、for循环

for循环是最常用的循环。有了while循环之后为什么还要有for循环呢?

仔细分析while的结构我们发现重复执行固定次数的循环中涉及到了三个行为:

1:初始化计数器;

2:计数器与有限值作比较(比如变量小于100,也就是说已知循环次数);

3:每次循环更新计数器。

当循环结构复杂、代码很多的时候,你想改变初始化的值或者循环条件或者更新机制可能会出现遗漏(因为他们很分散)。for循环的诞生解决了这一麻烦,它将初始化、比较、更新三个行为组合在一起,避免了问题。for循环结构:

for(表达式1;表达式2;表达式3)

          循环语句;

表达式1用于初始化循环变量,表达式2用于判断循环条件,表达式3用于循环条件的调整。

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int i = 0, a = 0;
	for (i = 1; i <= 100; i++)
	{
		a += i;
		printf("第%d次循环:\nsum=%d\n", i, a);
	}
	return 0;
}

break在for循环中的应用:

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int i = 0, a = 0;
	for (i = 1; i <= 100; i++)
	{
		if (i == 10)
			break;
		a += i;
		printf("第%d次循环:\n sum=%d\n", i, a);//只循环到第九次
	}
	return 0;
}

continue在for循环中的应用:

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int i = 0, a = 0;
	for (i = 1; i <= 100; i++)
	{
		if (i == 10)
			continue;
		a += i;
		printf("第%d次循环:\n sum=%d\n", i, a);
	}//跳过了i=10的情况
	return 0;
}

注意这里与while循环不一样,不会陷入死循环。因为遇到continue后不会执行循环体后面的语句,while循环中i++在循环体里面,而在for循环中i++在表达式3中不在循环体中,进而规避了这一情况。

你是不是也这样认为的?那你就出现了误区,i++虽然是在最后执行,但是它不算在循环体里面。

我们再回顾一下概念:跳过本次循环体中余下尚未执行的语句,立即进行下一次的循环条件判定。

它跳过的是循环体,i++不在循环体。所以for循环遇到continue语句,循环体内余下语句不在执行,然后执行i++,然后再进行条件的判定。

for循环的一些变种:

变种1:

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	for (;;)
		printf("haha\n");
	return 0;
}

这段代码会死循环打印haha。

请注意:

1、for循环的初始化,判断、更新都可以省略,但是for循环的判断被省略的话则默认判断恒为真,进而产生死循环;

2、尽量不要随意省略代码,下面的情况会导致代码出错。

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int i = 0;
	int j = 0;
	for (; i < 10; i++)
	{
		for (; j < 10; j++)
		{
			printf("haha\n");
		}
	}//打印出10个haha
return 0;
}

这个程序本意是想打印100个haha,但是输出结果为10个haha。这是因为在i=0循环结束后此时的j=10,当i=1时由于j=10并没有初始化为0,所以嵌套的for循环无法执行。

变种2:

使用了两个循环变量,比较少见。

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int x, y;
	for (x = 0, y = 0; x < 3 && y < 5; x++, y++)
	{
		printf("haha\n");
	}//打印三个haha
	return 0;
}

练习题:

下面的代码循环了多少次:

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int x, y;
	for (x = 0, y = 1; x = 0; x++, y++)
	{
		printf("haha\n");
	}
	return 0;
}

三、do...while循环

do...while循环用的比较少,它的结构是:

  do

      循环体(循环体可以是一个语句或有{ }起来的多条语句)

while(表达式);(注意此处有一个分号,而while循环和for循环没有)

例子:

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int sum = 0;
	int i = 1;
	do
	{
		sum += i;
		printf("前%d个数相加:\n sum=%d\n", i, sum);
		i++;
	} while (i <= 10);
	return 0;
}

C语言学习笔记之循环结构_第4张图片

 break语句在do...while循环中的应用:

C语言学习笔记之循环结构_第5张图片

和在while循环中没有什么区别。 

continue在do...while循环中的应用: 

C语言学习笔记之循环结构_第6张图片

出现了死循环,和在while循环中没有区别。 

四、goto语句

C语言提供了易被滥用的goto语句和标签名,这就导致程序运行的时候可能跳来跳去很容易产生bug。事实上,没有goto语句C程序也能正常运行,那为什么还要保留它呢?

C语言中不提倡使用goto语句,但有一种情况躲避不开:某些程序在处理多重嵌套的过程中,使用goto语句可以跳出多重循环,而break只能由这一层循环跳到上一层循环。

以下为几个简单的例子:

1、goto实现死循环

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int i = 0;
a:i++;
	printf("%d\n", i);
	goto a;//跳到a:继续执行
	return 0;
}

2、关机程序

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
int main()
{
	//shutdown -s为设置关机 -t为设置时间关机 shutdown -s -t 60为60秒后关机
	//快捷键win+r后输入cmd输入上面的代码电脑在60秒后关机,输入shutdown -a可以取消关机
	//system()用来执行系统命令
	char input[20] = { 0 };
	system("shutdown -s -t 120");
	again:
	printf("你的电脑将在120秒后关机,输入:我是傻瓜,可以取消关机\n请输入:\n");
	scanf("%s", input);
	if (strcmp(input, "我是傻瓜") == 0)
	{
		system("shutdown -a");
	}
	else
	{
		goto again;
	}

	return 0;
}

五、总结

1、continue只能在循环结构(for、while、do...while)中使用

2、break只能在Switch语句和循环结构中使用

3、do...while先执行循环体后判断条件,所以它至少执行一次循环体

4、for循环功能最强,最常使用

六、练习

1、计算n的阶乘

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int i = 0;
	int num = 0;
	double jieguo = 1;
	printf("请输入需要阶乘的数:");
	scanf("%d", &i);
	for (num = 1; num <= i; num++)
	{
		jieguo =jieguo* num;
	}
	printf("%d!的阶乘结果为:%lf",i, jieguo);
	return 0;
}

2、计算1!+2!+3!+...+n!

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int a = 0;
	int i = 1;
	int m = 1;
	int ret = 1;
	int sum = 0;
	printf("请输入你想前几个数的阶乘相加:");
	scanf("%d", &a);
	for (i = 1; i <= a; i++)
	{
		
		for (m = 1,ret=1; m <= i; m++)
		{//注意此处每次循环结束后需要初始化ret=1
         //如果不初始化,第一个for后面的循环中ret的值为上一个循环中ret的值
			ret = ret*m;
		}
		sum =sum+ ret;
	}
	printf("sum=%d", sum);
	
	return 0;
}

其实上面的代码具有优化的空间,原因是每计算一个数的阶乘还要从头开始计算,浪费资源。加入3的阶乘算完后我们算4的阶乘,那么直接在3 的阶乘上乘于4这样得到4的阶乘可以节省计算机资源。

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int i = 0;
	int ret = 1;
	int sum = 0;
	int a = 0;
	printf("请输入你想前几个数的阶乘相加:");
	scanf("%d", &a);
	for (i = 1; i <= a; i++)
	{
		ret = ret * i;
		sum = sum + ret;
	}
	printf("sum=%d", sum);
    return 0;
}

3、在一个有序数组中查找某个具体的数字n.

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int num = 6;//在有序数组中找到数字6
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	//其实就是求元素个数:数组所占空间总大小/单个元素所占空间大小
	for (i = 0; i < sz; i++)
	{
		if (num==arr[i])
		{
			printf("已找到,下标是:%d\n", i);
			break;
		}
	}
	if (i == sz)
		printf("无法找到\n");
    return 0;
}

上面的代码我们发现:当有序数组很大的时候,假设有n个元素,而你查找的元素为2^32,那么要查找2^32次,浪费时间。

有没有一种方法解决呢?

使用二分法:它只需要查找lg(n)-lg(2)次,也就是32次。

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
		int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21};
	int num = 0;
	printf("请输入想要找到的数字:");
	scanf("%d", &num);//想要找到的数字
	int sz = sizeof(arr) / sizeof(arr[0]);
	int left = 0;
	int right = sz - 1;
	int middle = (left + right) / 2;
		for (middle; left <=right; middle = (left + right) / 2)
		{
			if (arr[middle] > num)
			{
				right = middle - 1;
			}
			else if (arr[middle] < num)
			{
				left = middle + 1;
			}
			else
			{
				printf("已找到,下标是:%d\n", middle);
				break;
			}
		}
		
	if (left > right)
	{
		printf("查找不到\n");
	}
    return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21 };
	int num = 15;//想要找到的数字
	int sz = sizeof(arr) / sizeof(arr[0]);
	int left = 0;
	int right = sz - 1;
	int middle = (left + right) / 2;
	while (left <= right)
	{
		middle = (left + right) / 2;
		if (arr[middle] > num)
		{
			right = middle - 1;
		}
		else if (arr[middle] < num)
		{
			left = middle + 1;
		}
		else
		{
			printf("找到了,下标是%d\n", middle);
			break;
		}
	}
	if (left > right)
		printf("找不到\n");
    return 0;
}

4、编写代码使字符从两端向中间显现

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
int main()
{
	char arr1[] = "are you okay ??????";
	char arr2[] = "###################" ;
    //注:#换成空格观感更佳
	int left = 0;//左下标
	//int right = sizeof(arr1) - sizeof(arr1[0]) - 2;
	//注意这种方法需要减2,因为字符串后面有个隐藏的\0作为结束标志。
	int right = strlen(arr1) - 1;
	for (left, right; left <= right; left++, right--)
	{
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
	    system("cls");//执行系统命令的函数-cls-清空屏幕
        printf("%s\n", arr2);
		//为了显示打印效果可以让其隔一秒打印
		Sleep(1000);//单位是毫秒
	}
    return 0;
}

C语言学习笔记之循环结构_第7张图片

 5、编写代码使用户只能输入三次密码,密码正确则登录成功,三次均错误则退出程序

#define _CRT_SECURE_NO_WARNINGS
#include
#include
int main()
{
	char arr1[] = "suibianqiyige123";
	char arr2[20] = "0";
	int i = 1;
	for (i = 1; i < 4; i++)
	{
		printf("请输入密码:");
		scanf("%s", arr2);
		if (strcmp(arr1,arr2)==0)
		{
			//strcmp两个数组相等返回0,左边字符串大于右边的返回的值大于0,左边字符串小于右边的返回的值小于0
			//注意==不能判断两个数组是否相等
			printf("登录成功!\n");
			break;
		}
		else
		{
			if (i < 3)
			{
				printf("密码错误,请重新登录!\n");
			}
			else;
		}
	}
	if (i == 4)
		//system("cls");
		printf("三次错误登录,请退出登录!\n");
	return 0;
}

你可能感兴趣的:(C语言学习,学习,笔记,c#,c语言)