C语言提供了重复执行某行代码的语句
分为三种
while、do、for三种语句
一、while语句
while(/*逻辑表达式*/)//控制语句
{
//循环体;
}
while是最简单的循环,分为两个部分控制语句和循环体
控制语句由while关键字和圆括号里的逻辑表达式共同组成
当程序执行到while语句时
会先判断while(/*逻辑表达式*/)中的表达式的结果
此时
1.表达式结果为1
执行一次循环体内容
如果循环体中的内容正常结束
则从重新从while(/*逻辑表达式*/)开始执行
2.表达式结果为0
不执行循环体内容,直接结束while语句
注意:
循环体不是非加{}不可
加{}执行整个{} 作用域中的内容
如果不加则只执行第一个;换行前的内容
二、do语句(do while语句)
do
{
//循环体
}
while (/*逻辑表达式*/) ;//控制语句
do语句其实也是while循环语句,必须依赖while语句,我们知道while语句是先判断逻辑表达式根据判断结果判断是否执行循环体,如果while语句的控制语句未通过,循环体是一次也不会执行的。
但是do while语句就不一样了,程序第一次执行到do while时,直接先执行一次do中的循环体
我们可以用流程图来理解一下两种循环的区别
三、for语句
for语句的格式如下(C99)
for(声明或者表达式1;表达式2;表达式3)循环体
为了理解for循环可以使用这个等价while循环
表达式1;
while(表达式2)
{
{循环体}
{表达式3;}
}
分析后可以了解for循环的作用
表达式1:初始化语句,一般用于初始化自增变量
表达式2:判断表达式,用于限制显示条件
表达式3:变化表达式,用于满足表达式2的动态变化
并有以下结论
for循环的执行顺序如等价中的while的顺序是相同的,也就是说,表达式1和表达式2必定被执行,表达式3不一定能执行到,但表达式1只会执行一次
for语句中的省略表达式
看了for等价while之后,可以发现,除了表达式2,剩下的表达式1、表达式3都可以省略掉
最精简可以精简到
for(;1 ;)
{
printf("嗨害嗨!\n");
}
这样相当于下方的while死循环
while(1)
{
printf("嗨害嗨!\n");
}
显然这个还不如直接是使用while循环看的清晰
for循环常用方法是可以较为方便的控制循环次数
for(int i = 0 ;i < 5 ;i++)
{
printf("1111\n");
}
这样代表循环从0开始循环,当i达到 5时直接结束循环
C89和C99的for循环是有区别的
我在这一部分上面写的for语句都是C的写法,C89和C99的for语句的区别在下面
首先C89的表达式1中不可存在声明语句,如果写了,编译会报错
C89错误写法(但C99中可以这样写)
for(int i = 0 ;i < 5 ;i++)//此处会报错
{
printf("1111\n");
}
C89正确写法(但C99中可以这样写)
int i;
for(i = 0 ;i < 5 ;i++)//此处会报错
{
printf("1111\n");
}
显然C99的for语句的语法更人性化一点
C89不能兼容C99特有的写法,C99则可以使用两种写法,这就引申出了另一个问题:
上面两个引用框的i值作用域不一样
上面的i作用域只在for循环内,下面的i在最外侧作用域
for(int i = 0 ;i < 5 ;i++)
{
printf("1111\n");
}
printf("i = %d \n",i);//这样写直接报错 i会显示没有定义
同样会引申出另一个问题
int i = 5;
for(int i = 0 ;i < 5 ;i++)
{
printf("1111\n");
}//这么写是合法的,看似int i被定义了两次 但是表达式1的作用域比上面的作用域小,也就是说进入表达式后i的值只从0开始
进阶一些的理解就是
int i = 5;
{
int i = 0;
while(i<5)
{
//循环体
i++;
}
}
逗号运算符在for循环中的作用
首先回顾一下“,”运算符的作用
一般作用:在多个一般表达式之间进行分割,为多个同种变量的声明省略类型,如下
int i = 0,j = 10 ;
可以连续定义两个int型变量但只需写一个int,并且可以继续追加
我们利用,运算符做些什么呢?比如使用同时遍历两个条件的时候,我们可以使用,号追加条件
for(int i = 0,j = 10 ;i < 5 , j >6 ;i++,j--)
{
printf("i == %d , j = %d \n",i,j);
}
输出为
i == 0 , j = 10
i == 1 , j = 9
i == 2 , j = 8
i == 3 , j = 7
注意!!!!:这个判断表达式这个,号把两个显示条件连接起来时有点类似于&&的作用,当然最好是直接用&&更清晰一些
所有的的表达式都可以自由发挥,放飞自我的去写,即使简单如for语句也是可以玩出花儿的
四、结束循环的方式
退出循环除了等到控制表达式为false还有主动跳出循环的几种方式
1)break:
跳出当前循环或控制
如,现在军队里现在有20吨粮食,每天吃掉4吨,当前粮食能否坚持到6天时间,如果不行,能坚持几天?
分析问题粮食吃完了,在计算没有意义,以i为天 j为粮食数
for(int i = 0,j = 20;i < 6;++i,j-=4)
{
printf("day i = %d ,food j = %d \n",i,j);
if(0 >= j)
break;
}
输出
day i = 0 ,food j = 20
day i = 1 ,food j = 16
day i = 2 ,food j = 12
day i = 3 ,food j = 8
day i = 4 ,food j = 4
day i = 5 ,food j = 0
计算得出 第五天结束 粮食就吃完了 根本坚持不了6天
注意:只能跳出一层嵌套 也就是说,出现多层循环嵌套时,如果在内层循环跳出,只能跳出当前循环,外层循环仍然继续
2)continue:
结束当前循环体,注意,结束循环体和结束循环的区别,循环体是循环语句中被循环的部分
循环是整个循环,区别是什么呢?
int a = 0;
while(a < 10)
{
if(0 == (a%2))
continue;
printf("while = %d \n",a);
a ++;
}
for(int i = 0;i < 10;++i)
{
if(0 == (i%2))
continue;
printf("for = %d \n",i);
}
上方有两个循环 同样是打印10以内的奇数
while循环的变量自增我们写在循环体内,我们没有经过自增就重新进入判断语句上,这样就会导致出现死循环,导致程序阻塞或者崩溃
而for循环的自增是紧随循环体之后的,也就是说,即使循环体被continue中断,紧接着还是会正常自增的,因为这个自增一定会触发控制语句的false条件,所以单独运行下方for循环时不会崩溃
如果有傲娇的小伙伴表示自己就是想用while循环呢
使用以下代码
int a = 0;
while(++a < 10)
{
if(0 == (a%2))
continue;
printf("while = %d \n",a);
// a ++;
}
既然while循环循环体会被中断,那干脆在控制表达式中自增算了(注意:必须为前缀自增),当然,你不怕被师傅打爆头的情况下(狗头),但是,强烈不建议如此实现,与其如此,不如不使用continue 如下
int a = 0;
while(a < 10)
{
if(1 == (a%2))
{
printf("while = %d \n",a);
}
++a;
}
看到此是不是又觉得continue 作用不大?也并非如此,无论是哪种跳出,都是期待我们减少后续无用代码的运算,以提高程序的运行效率,减少无意义的计算,上面写的这种代码量很少,实际开发中又很多需要在循环中提前中断的地方
3)goto:(不建议使用)
语法
标签名:
goto 标签名;
执行语句时,我们可以向任意标签跳转
int a = 0;
n1:
printf("ahahahah xian !!!\n");
while(a < 10)
{
if(1 == (a%2))
{
printf("while = %d \n",a);
++a;
goto n1;
}
printf("++while = %d \n",a);
++a;
}
输出
ahahahah xian !!!
++while = 0
while = 1
ahahahah xian !!!
++while = 2
while = 3
ahahahah xian !!!
++while = 4
while = 5
ahahahah xian !!!
++while = 6
while = 7
ahahahah xian !!!
++while = 8
while = 9
ahahahah xian !!!
ahahahah !!!
我们甚至可以跳转到int a定义之前来把循环变为死循环(变态脸)
这也是goto语句容易出问题的原因之一,很多变态的错误在等待我们踩坑(玩笑)
主要是不建议使用
因为break、continue、return本身就是受限制的goto,正常开发这些就已经能解决所有问题了