(如有错误请指出)
所谓循环结构就是在给定条件成立时,重复执行某段程序。循环结构中,给定的条件称为循环条件,重复执行的程序叫做循环体。C语言中有for、while、do...while三种循环语句实现循环结构。
目录
一、while循环
二、for循环
三、do...while循环
四、goto语句
五、总结
六、练习
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--少了一个循环。
break语句只用在Switch语句和循环语句中,在循环语句的作用是跳出循环体,去执行循环体后面的程序,和Switch语句中的作用类似。下面的程序在a=90的时候遇到break,跳出循环语句所以只循环了10次。
continue语句只能用于循环结构,作用是结束本次循环,不再执行循环体中continue之后的语句,转而跳转到判断循环条件(也就是while()这一段程序)。
上面的这段程序在a=10的时候执行continue语句所以跳转到while(a<=100)继续执行然后又跳转回来,陷入死循环。然而只需要改变一个语句的位置就可解除危机。我们发现陷入死循环的原因是a的值一直为10,那么我们仅需要把a++放在循环体中continue语句之前就可以解决问题。而付出的代价是:a=10这一情况被跳过。而若想在计算100!过程中跳过a=10这一情况需要这样改动:
break语句和continue语句的区别在于:break终止整个循环体的执行,跳出循环体执行它后面的程序,不去判断循环条件;而continue终止此次循环,跳转到判断循环条件是否成立这一步。
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(表达式);(注意此处有一个分号,而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;
}
break语句在do...while循环中的应用:
和在while循环中没有什么区别。
continue在do...while循环中的应用:
出现了死循环,和在while循环中没有区别。
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;
}
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;
}