[深入浅出C语言]浅析控制语句(后篇)

62 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

前言

        本文为C语言控制语句的第二篇,主要介绍了控制语句中的循环语句和转向语句,主要基于笔者的学习经验和心得所作。

        由于笔者水平有限,文章拙劣而纰漏难免,欢迎指正,希望于你有益。

循环语句和转向语句

while语句

       当满足while()括号里的条件也就是括号内表达式为真时,执行while后面语句,直到表达式值为假为止。

while(exp)
{
    //...可以是各种语句
}

image.png

break语句在while中的作用

        其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。

        若是有循环嵌套的话break只能跳出一层循环,若是循环里的if语句里的,一样跳出循环。

        所以:while中的break是用于永久终止循环的。

continue在whlie循环中的作用

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

一点题外话

        遇到这个问题不要慌,因为已经打开了这个可执行程序所以无法再打开,只需要把原先打开的.exe关掉就行。

image.png

        好的习惯:声明变量时初始化值。

for语句

        for()语句括号内有三个表达式,分别对应初始化操作,循环判断条件和循环后调整。

for(exp1; exp2; exp3)
{
    //...可以是各种语句

}

image.png

        可以发现在while循环中依然存在循环的三个必须条件,但是由于风格的问题使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。

        所以,for循环的风格更胜一筹,for循环使用的频率也最高。 

        我们发现在for循环中也可以出现break和continue,break的话和while中的作用差别不大,但是continue就有所不同了。

continue在for中的作用

        当i等于5时,会跳转到哪里呢?

image.png

        如果跳转到1处或3处的话,i的值都没有更新,也就是跳过了条件更新,最终会导致死循环,是不是这样呢?我们让代码跑起来看看。

image.png

        很明显,i的值一直在更新,所以continue在for中是跳转到条件更新处而非条件判断处的。

注意事项

  1. 不可在for 循环体内修改循环变量,防止 for 循环失去控制。

  2. for循环遵循前闭后开区间,比如for(i = 0; i < 10; i++)也就是i的取值区间为[0,10),更为直观,循环次数明确,比如前面的循环一看就知道要循环10次;便于个数计算,比如for(j = 6; j < 10; j++)直接10-6=4就算出了个数。**

  3. for循环中的初始化部分,判断部分,调整部分是可以省略的,可以省略一个或多个表达式(但是不能省略分号),但是不建议初学时省略,容易导致问题,尤其是判断部分,如果省略的话意味着条件恒成立,会无限循环下去。

  4. 第一个表达式不一定是给变量赋初值,也可以使用printf()。在执行循环的其他部分之前,只对第一个表达式求值一次或执行一次。

  5. for(int i = 0; ; )在初始化部分创建变量并初始化,C99标准才支持,C++也支持。

  6. 可以使用不止一个变量控制循环

  int x, y;
  for (x = 0, y = 0; x<2 && y<5; ++x, y++)
   {
      printf("hehe\n");
   }
  1. 嵌套循环时,尽量把长的循环放内层,短的循环放外层,也就是外小内大,有利于减少循环来回跳转的次数,一般效率会高一些。

do...while循环

        循环至少执行一次,使用的场景有限,所以不是经常使用。

image.png

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可以互相嵌套,任意组合。

        要注意的是,内层循环在每次外层循环迭代时都执行完所有的循环,所以嵌套循环的执行次数是内外层循环次数的乘积。

例题剖析

        看看这个循环怎么样。

image.png

        死循环了,一旦i等于5了,就无法再对循环变量进行调整。

        上述代码本来的想法应该是:循环10次,每次循环时如果i==5则打印i的结果。

        但if语句中表达式的==写成了赋值,相当于每次循环尽量都是将i的值设置成了5,5为真,因此每次都会打印5。

        i每次修改成5打印后,i的值永远不会等于10,因此造成死循环。

        结果就是死循环地打印5。

goto语句

        C语言中提供了可以随意使用的 goto语句和标记跳转的标号。

        从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。

        但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。

        例如:一次跳出两层或多层循环。 多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。

image.png

        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,想想看,还有什么办法没?

看看这个:

image.png

切掉长出来的部分,然后让长出来的部分对半切,再一边一半:

image.png

这下就有办法了: (right - left) / 2 + left


以上就是本文全部内容了,感谢观看,你的支持就是对我最大的鼓励~

v2-59236a6ecd3ce9462e530ae78b3b9e3f_720w.jpg