携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情
前言
本文为C语言控制语句的第二篇,主要介绍了控制语句中的循环语句和转向语句,主要基于笔者的学习经验和心得所作。
由于笔者水平有限,文章拙劣而纰漏难免,欢迎指正,希望于你有益。
循环语句和转向语句
while语句
当满足while()括号里的条件也就是括号内表达式为真时,执行while后面语句,直到表达式值为假为止。
while(exp)
{
//...可以是各种语句
}
break语句在while中的作用
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
若是有循环嵌套的话break只能跳出一层循环,若是循环里的if语句里的,一样跳出循环。
所以:while中的break是用于永久终止循环的。
continue在whlie循环中的作用
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。
一点题外话
遇到这个问题不要慌,因为已经打开了这个可执行程序所以无法再打开,只需要把原先打开的.exe关掉就行。
好的习惯:声明变量时初始化值。
for语句
for()语句括号内有三个表达式,分别对应初始化操作,循环判断条件和循环后调整。
for(exp1; exp2; exp3)
{
//...可以是各种语句
}
可以发现在while循环中依然存在循环的三个必须条件,但是由于风格的问题使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。
所以,for循环的风格更胜一筹,for循环使用的频率也最高。
我们发现在for循环中也可以出现break和continue,break的话和while中的作用差别不大,但是continue就有所不同了。
continue在for中的作用
当i等于5时,会跳转到哪里呢?
如果跳转到1处或3处的话,i的值都没有更新,也就是跳过了条件更新,最终会导致死循环,是不是这样呢?我们让代码跑起来看看。
很明显,i的值一直在更新,所以continue在for中是跳转到条件更新处而非条件判断处的。
注意事项
不可在for 循环体内修改循环变量,防止 for 循环失去控制。
for循环遵循前闭后开区间,比如for(i = 0; i < 10; i++)也就是i的取值区间为[0,10),更为直观,循环次数明确,比如前面的循环一看就知道要循环10次;便于个数计算,比如for(j = 6; j < 10; j++)直接10-6=4就算出了个数。**
for循环中的初始化部分,判断部分,调整部分是可以省略的,可以省略一个或多个表达式(但是不能省略分号),但是不建议初学时省略,容易导致问题,尤其是判断部分,如果省略的话意味着条件恒成立,会无限循环下去。
第一个表达式不一定是给变量赋初值,也可以使用printf()。在执行循环的其他部分之前,只对第一个表达式求值一次或执行一次。
for(int i = 0; ; )在初始化部分创建变量并初始化,C99标准才支持,C++也支持。
可以使用不止一个变量控制循环
int x, y; for (x = 0, y = 0; x<2 && y<5; ++x, y++) { printf("hehe\n"); }
- 嵌套循环时,尽量把长的循环放内层,短的循环放外层,也就是外小内大,有利于减少循环来回跳转的次数,一般效率会高一些。
do...while循环
循环至少执行一次,使用的场景有限,所以不是经常使用。
int main()
{
int i = 1;
do
{
if(5 == i)
continue;
printf("%d\n", i);
i++;
}while(i<10);
return 0;
}
break和continue在while和do...while中作用一样。
上面代码中会陷入死循环,因为一旦i的值等于5,就一直跳过后面的代码,i的值一直不会改变,也就一直满足循环条件i < 10
而不断循环。
循环嵌套
是指在一个循环内包含另外一个或多个循环,在外面的被称为外层循环,在里面的被称为内层循环。
比如:
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
{
printf("* ");
}
printf("\n");
}
可以分别用来处理行和列的数据。
for和while以及do...while可以互相嵌套,任意组合。
要注意的是,内层循环在每次外层循环迭代时都执行完所有的循环,所以嵌套循环的执行次数是内外层循环次数的乘积。
例题剖析
看看这个循环怎么样。
死循环了,一旦i等于5了,就无法再对循环变量进行调整。
上述代码本来的想法应该是:循环10次,每次循环时如果i==5则打印i的结果。
但if语句中表达式的==写成了赋值,相当于每次循环尽量都是将i的值设置成了5,5为真,因此每次都会打印5。
i每次修改成5打印后,i的值永远不会等于10,因此造成死循环。
结果就是死循环地打印5。
goto语句
C语言中提供了可以随意使用的 goto语句和标记跳转的标号。
从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。
但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。
例如:一次跳出两层或多层循环。 多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。
goto只能在同一个函数内跳转,它无法从一个函数跳转到另一个函数去。
二分查找
在查找的时候怎样设计代码比较好?
比如你在和朋友玩猜数字游戏,他心里想一个一定范围内的数字,假设是0~1000以内,在规定时间内,要你猜一猜,你会怎么猜?当然不可能1,2,3…一点一点猜呀,大家估计都是先对半砍一下——500,不对,小了;那就750,不对还是小了;那825,大了;那……一半一半地砍下去能够很快的缩小查找区间,转眼间就接近目标数字了。
那在我们设计查找方法的代码的时候就有了二分查找的办法。
int main()
{
int targ = 0;//查找目标
int arr[10] = {1, 2, 4, 5, 6, 7, 8, 9, 10, 11};
int num = sizeof(arr) / sizeof(arr[0]);//数组元素个数
printf("请输入要查找的元素:\n");
scanf("%d", &targ);
int left = 0;
int right = num - 1;
int mid = 0;
for (; left <= right;)
{
mid = (right - left) / 2 + left;
if (targ < arr[mid])
{
right = mid - 1;
}
else if (targ > arr[mid])
{
left = mid + 1;
}
else
{
printf("找到%d了,对应数组下标为:%d\n", targ, mid);
break;
}
}
if (left > right)
printf("找不到");
return 0;
}
注意mid的取值,如果是(left + right) / 2的话,想想看,left+right有没有越界的可能,当数值非常大的时候可能存在溢出,再除于2的话值就不是我们想要的中间值了。那怎么办?
先看看这样一个问题:
我有两根木棒,把它们立起来,现在我想要“取长补短”,让两木棍一样长,但我不想用(长+短)/2,想想看,还有什么办法没?
看看这个:
切掉长出来的部分,然后让长出来的部分对半切,再一边一半:
这下就有办法了: (right - left) / 2 + left。
以上就是本文全部内容了,感谢观看,你的支持就是对我最大的鼓励~