【C语言-循环结构】啃透C语言的循环结构,把这些搞明白你就稳了

开发技术 作者: 精灵星空 SKY315.COM 更新于: 浏览: 241
码字发文不易,转载请注明出处【精灵星空 SKY315.COM】

说实话,循环结构在C语言里算不上最难的东西,指针比它绕多了。但你要说它重不重要?我跟你讲,任何稍微有点实际意义的程序,都离不开循环。你想想,让你算1加到100,没有循环你不得写到天荒地老?让你从一堆数据里找到最大值,没循环你只能干瞪眼。

很多人学循环的时候觉得“这有啥难的,不就是while和for嘛”,结果一到写代码就翻车——死循环跑得电脑嗡嗡响,或者循环次数怎么都对不上。说白了就是没真正理解循环背后的执行逻辑,光记住语法格式了。

下面我把C语言里跟循环相关的知识点从头捋一遍,配上几个典型例子,你看完要是还迷糊,来找我。

C语言在线编程环境:https://sky315.com:8080/c/。

一、三种循环结构,各自什么来头?

C语言提供了三种循环:while、do-while、for。它们都能实现重复执行,但各有各的脾气。

while循环——先看门再进门

语法格式长这样:

        while (条件表达式) {
            循环体语句;
        }

执行逻辑就一句话:先判断条件,条件为真就进循环体跑一遍,跑完再回来判断,直到条件为假跳出。如果一开始条件就是假的,循环体一次都不执行。

do-while循环——先进门再说

        do {
            循环体语句;
        } while (条件表达式);

跟while唯一的区别:先执行一次循环体,再判断条件。也就是说,不管条件成不成立,do-while至少给你跑一次。这个特性有时候特别好使。

for循环——计数器的好兄弟

        for (表达式1; 表达式2; 表达式3) {
            循环体语句;
        }

for循环的三个表达式各司其职:

  • 表达式1:初始化,在循环开始前执行一次

  • 表达式2:循环条件,每次循环开始前判断,真就执行,假就退出

  • 表达式3:每轮循环结束后执行,通常用来更新循环变量

执行顺序是:1→判断2→真就进循环体→执行3→再判断2→真再进循环体→执行3……直到判断2为假。

很多人搞不清楚的是,表达式1只执行一次,别以为它每轮都跑。还有,三个表达式都可以省略,但两个分号不能省。for(;;)就是一个死循环,跟while(1)一个意思。

二、循环控制语句——break和continue,别搞混了

这两个关键字是专门用来在循环内部“搞事情”的,很多人用混了,后果天差地别。

break:直接跳出当前循环,循环结束,继续执行循环后面的代码。注意是“跳出整个循环”,不是只跳一次。

continue:结束本轮循环,跳过本轮循环体后面还没执行的语句,直接进入下一轮循环。循环没结束,只是这次不干了,下次继续。

区别说白了就是:break是“我不玩了,走了”,continue是“这次我不干了,下次再说”。

三、典型例题挨个讲,比光看语法管用多了

光说语法你记不住,咱们上例子。这几个例子都是最经典的,你挨个看懂,循环的基本功就差不多了。

例1:计算1+2+3+...+100的和

这个题虽然简单,但三种循环写法你都得会,体会它们的不同。

用for循环:

        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }

用while循环:

        int sum = 0, i = 1;
        while (i <= 100) {
            sum += i;
            i++;
        }

用do-while循环:

        int sum = 0, i = 1;
        do {
            sum += i;
            i++;
        } while (i <= 100);

你看,for循环把初始化、条件、更新三件事搁一块了,最紧凑。while把条件放前面,do-while先干再说。结果都一样,但for循环最适合这种“知道要循环多少次”的场景。

例2:从键盘输入一堆整数,以0结束,求平均值

这个例子有意思,因为循环次数不确定,你事先不知道用户会输几个数。

        int num, sum = 0, count = 0;
        float avg;

        printf("请输入整数,输入0结束:\n");
        while (1) {
            scanf("%d", &num);
            if (num == 0) {
                break;
            }
            sum += num;
            count++;
        }

        if (count > 0) {
            avg = (float)sum / count;
            printf("平均值:%.2f\n", avg);
        }

为什么用while(1)?因为循环次数未知,用无限循环配合break退出更灵活。用户输0的时候break直接跳出去,干净利落。

例3:输出1到100之间所有能被3整除的数

这题考的是continue的用法。

        for (int i = 1; i <= 100; i++) {
            if (i % 3 != 0) {
                continue;    // 不能被3整除?跳过这次,不打印
            }
            printf("%d ", i);
        }

i=1的时候,1%3不等于0,continue一执行,后面printf就不跑了,直接进入i=2的下一轮。i=3的时候,3%3等于0,条件不成立,continue不执行,正常打印。continue在这里就像个筛子,把不符合条件的筛掉。

你不用continue也能写:

        for (int i = 1; i <= 100; i++) {
            if (i % 3 == 0) {
                printf("%d ", i);
            }
        }

但有时候用continue能让代码逻辑更清晰——先排除特殊情况,再处理正常逻辑。

例4:打印9×9乘法表

这题考的是循环嵌套,就是循环里面再套循环。

        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= i; j++) {
                printf("%d×%d=%-4d", j, i, i * j);
            }
            printf("\n");   // 每行结束换行
        }

外层循环控制行数(1到9行),内层循环控制每行打印几个式子。注意内层条件是j <= i,不是j <= 9——这样打印出来是下三角形状,j不会超过i。你要是写成j <= 9,那就打印成矩形了,乘法表就不是那个味儿了。

例5:判断一个数是不是素数

素数就是只能被1和自身整除的数。这题考的是循环什么时候结束。

        int num, i, flag = 1;
        scanf("%d", &num);

        if (num <= 1) {
            flag = 0;  // 1和负数不是素数
        } else {
            for (i = 2; i < num; i++) {
                if (num % i == 0) {
                    flag = 0;
                    break;   // 找到一个因子就够了,不用再找了
                }
            }
        }

        if (flag == 1) {
            printf("%d是素数\n", num);
        } else {
            printf("%d不是素数\n", num);
        }

这里的break用得妙。一旦发现num能被某个i整除,说明它不是素数,后面不用再判断了,直接break跳出。你要是不用break,循环会一直跑到i=num-1,虽然结果一样但效率低不少。

优化一下:其实循环条件可以写成i <= sqrt(num),因为如果一个数有因子,必定有一个因子不大于它的平方根。这个优化思路你以后学了数学函数就知道了。

四、几个容易踩的坑,提前告诉你省得你折腾

坑1:分号放错地方

        for (i = 1; i <= 100; i++);   // 注意这个分号!
        {
            sum += i;
        }

for后面直接跟了个分号,循环体就成了空语句。循环默默跑了100次,啥也没干,然后才执行后面大括号里的sum += i,这时候i已经是101了。这种Bug编译器不报错,肉眼还不好找,特别恶心。

坑2:死循环

        while (i <= 100) {
            sum += i;
            // 忘记写 i++;
        }

i永远不变,条件永远为真,电脑风扇转得飞起,程序永远不结束。写while循环一定记得更新循环变量。for循环这方面好一些,更新条件写在表达式3里,不太容易忘。

坑3:浮点数当循环条件

        for (float x = 0.0; x != 1.0; x += 0.1) {
            // 这循环可能停不下来
        }

浮点数在计算机里存的是近似值,0.1累加10次可能变成0.999999而不是1.0,x != 1.0永远为真。循环条件最好用整数,或者用<、>关系运算符,别用==或!=。

坑4:break只跳一层循环

嵌套循环里,break只能跳出它所在的那一层循环,外层的继续跑。想一次性跳出来?要么用goto(不推荐),要么加标志变量。

五、总结几句

循环结构说白了就三条:while先判断再执行,do-while先执行再判断,for适合固定次数。break是直接跳出来不玩了,continue是这次不干了下次再说。

你把这几个例子自己敲一遍,跑一跑,把循环次数、变量变化过程在脑子里过一遍,能做到看一段循环代码就知道它执行几次、每轮变量变成啥,那你循环这块就算彻底过关了。

别光看我写的,打开编译器,自己动手。代码这东西,看十遍不如敲一遍出一次错,出一次错修好了顶你看十遍。去练吧。