4 C 语言控制流与循环结构的深入解读

news2024/11/15 7:22:17

目录

1 复杂表达式的计算过程

2 if-else语句

2.1 基本结构及示例

2.2  if-else if 多分支

2.3 嵌套 if-else

2.4 悬空的 else

2.5 注意事项

2.5.1 if 后面不要加分号

2.5.2 省略 else

2.5.3 省略 {}

2.5.4 注意点

3 while 循环

3.1 一般形式

3.2 流程特点

3.3 注意事项

3.3.1 while 后面不能加分号

3.3.2 使用花括号括起循环体

4 do-while 循环

4.1 一般形式

4.2 注意事项

5 for 循环

5.1 一般形式

5.2 执行过程

5.3 省略写法

5.3.1 省略初始化表达式

5.3.2 省略循环条件表达式

5.3.3 省略更新表达式

5.3.4 省略所有表达式

5.4 注意事项

5.4.1 for后面不能加分号

5.4.2 循环条件的正确性

6 三种循环的选择

6.1 for循环

6.2 while循环

6.3 do-while循环

7 continue 语句

7.1 语法及示例

7.2 注意事项

7.2.1 对于while循环

7.2.2 对于do-while循环

8 break 语句

8.1 语法及示例

8.2 注意事项

8.2.1 只会跳出当前所在的最内层结构

8.2.2 适用范围

9 小节判断题

10 OJ 练习

10.1 课时4作业1

10.2 课时4作业2

10.3 课时4作业3


1 复杂表达式的计算过程

程序员控制程序执行逻辑运算需要选择循环结构,首先我们来讲选择语句,在介绍选择语句前,我们首先练习一下关系表达式与逻辑表达式。在第 3 章内容中,我们了解到算术运算符的优先级高于关系运算符、关系运算符的优先级高于逻辑与和逻辑或运算符、相同优先级的运算符从左至右进行结合等 ,简单记就是: ! > 算术运算符 > 关系运算符 > && > || > 赋值运算符,那么表达式 5>3&&8<4-!0 的最终值是多少?计算过程是怎样的?

大部分人容易想成以下错误的计算过程:

  1. 首先,分析表达式 5 > 3 && 8 < 4 - !0 。
  2. 先计算 !0 ,! 是逻辑非运算符,0 表示假,!0 就表示真,即值为 1 。
  3. 然后计算 4 -!0 ,即 4 - 1 ,结果为 3 。
  4. 接着计算 5 > 3 ,这是成立的,值为真,即 1 。
  5. 再计算 8 < 3 ,这是不成立的,值为假,即 0 。
  6. 最后计算 1 && 0 ,&& 是逻辑与运算符,只有当两个操作数都为真时结果才为真,所以整个表达式的值为假,即 0 。

然而,正确的计算过程是:先计算 5 > 3 ,因为 && 的短路性质,具体步骤如下图所示:


2 if-else语句

在你打开衣柜拿出最上面的一件衣服时,你会判断这件衣服是不是你想穿的。如果是,那么你就会穿上;如果不是,那么你就会去找其他衣服。在计算机中,我们用“如果”判断语句来实现这样的效果:“如果”判断条件(表达式)为真,就执行某个语句,反之不执行这个语句。当然,也可以“如果”判断条件(表达式)为真,就执行某个语句,反之用“否则”分支执行另一个语句,具体流程如下图 1 和图 2 所示。

在 C 语言中,if-else 语句是一种基本的控制流语句,用于根据条件表达式的真假来执行不同的代码块。这种结构允许程序进行条件判断,并根据判断结果执行相应的操作。

2.1 基本结构及示例

if-else 语句的基本结构如下:

if (condition) {  
    // 如果condition为真(true),则执行这里的代码  
} else {  
    // 如果condition为假(false),则执行这里的代码  
}
  • condition:是一个表达式,其结果必须是整型(在C语言中,非零值被视为,零被视为)。
  • if 后的花括号 {} 内包含了当 condition 为时要执行的语句。
  • else 后的花括号 {} 内包含了当 condition 为时要执行的语句。

示例1:

假设我们要编写一个程序,根据用户输入的年龄来判断其是否成年:

#include <stdio.h>

int main() {
    int age;
    printf("请输入你的年龄: ");
    fflush(stdout); //解决Clion中printf和scanf顺序问题
    scanf("%d", &age);

    if (age >= 18) {
        printf("你已成年。\n");
    } else {
        printf("你还未成年。\n");
    }

    return 0;
}

在上面这个例子中,程序首先提示用户输入年龄,然后通过一个 if-else 语句来判断年龄是否大于等于18岁。根据判断结果,程序会输出相应的信息。

输出结果如下图所示:

示例2:

判断输入值是否大于 0 ,当输入值大于 0 时,打印 “i 是大于 0”,当输入值小于等于 0 时,打印 “i 不是大于 0”,具体代码如下例所示:

#include <stdio.h>

int main() {
    int i;
    // 这里使用while循环主要是为了多次运行程序,一次一次启动浪费时间
    while(scanf("%d",&i))
        if(i>0){//不要在括号后加分号
            printf("i is bigger than 0\n");
        }
        else{
            printf("i is not bigger than 0\n");
        }
    }
    return 0;
}

2.2  if-else if 多分支

“if 语句”和“else 语句”也可以多个同时使用(多分支语句),如下图 3 所示。

else if 是 else 语句后紧跟着另一个 if 语句的简写,它允许你在一个 if-else 结构中测试多个表达式。如果 if 语句的条件为假,则程序会检查 else if 的条件;如果 else if 的条件也为假,则继续检查下一个 else if(如果有的话);如果所有的 if 和 else if 条件都为假,并且存在一个 else 分支,则执行 else 分支中的代码。

如下面这个例子,根据用户输入的分数,程序会输出不同的评级:

#include <stdio.h>  
  
int main() {  
    int score;  
    printf("请输入分数(0-100): ");  
    scanf("%d", &score);  
  
    if (score >= 90) {  
        printf("优秀\n");  
    } else if (score >= 80) {  
        printf("良好\n");  
    } else if (score >= 60) {  
        printf("及格\n");  
    } else {  
        printf("不及格\n");  
    }  
  
    return 0;  
}

在使用 if-else if 结构创建多分支时,无论有多少个 if 语句或 else if 语句,程序都只会执行这些条件语句中的一个。这是因为程序会按照顺序检查每个条件,一旦找到第一个为真的条件,就会执行与之对应的代码块,并跳过剩余的所有 else if 和 else 分支。

如果所有的 if 和 else if 条件都不满足(即为假),并且存在 else 分支,则程序会执行 else 分支中的代码。如果连 else 分支也没有,那么程序将不会执行任何 if-else if-else 结构中的代码,而是继续执行该结构之后的代码。

下面是一个简单的示例,说明了这个过程:

#include <stdio.h>  
  
int main() {  
    int number = 5;  
  
    if (number == 1) {  
        printf("Number is 1\n");  
    } else if (number == 2) {  
        printf("Number is 2\n");  
    } else if (number == 5) {  
        printf("Number is 5\n"); // 这个条件为真,因此会执行这个分支  
    } else if (number == 10) {  
        printf("Number is 10\n"); // 这个条件为假,因此不会执行  
    } else {  
        printf("Number is not 1, 2, 5, or 10\n"); // 也不会执行到这个分支  
    }  
  
    return 0;  
}

2.3 嵌套 if-else

else if 是处理多条件判断的首选方式,但在某些情况下,可能需要嵌套 if 语句,即在一个 if 或 else 代码块内部使用另一个 if 语句。

 在下面这个例子中,我们首先检查年龄,然后根据年龄的结果,我们进一步检查身高。

#include <stdio.h>  
  
int main() {  
    int age, height;  
  
    printf("请输入年龄: ");  
    scanf("%d", &age);  
    printf("请输入身高(厘米): ");  
    scanf("%d", &height);  
  
    if (age >= 18) {  
        if (height >= 170) {  
            printf("您已经成年且身高达到或超过170厘米。\n");  
        } else {  
            printf("您已经成年但身高不足170厘米。\n");  
        }  
    } else {  
        printf("您还未成年。\n");  
    }  
  
    return 0;  
}

2.4 悬空的 else

在 C 语言中,当使用嵌套的 if 语句时,必须明确每个 else 子句与哪个 if 语句相关联,以避免所谓的“悬空的 else ”问题。这个问题通常发生在有多个 if 语句连续出现,并且至少有一个 if 语句后面跟着一个 else 语句时。

编译器会根据大括号 {} 的嵌套来解析 else 子句与哪个 if 语句相关联,但如果没有明确使用大括号来限定每个 if 语句的作用域,那么 else 子句就会与最近的、尚未与 else 子句关联的 if 语句相匹配

示例:没有使用大括号的悬空else问题

#include <stdio.h>  
  
int main() {  
    int a = 1, b = 2;  
  
    if (a > b)  
        if (a == 1)  
            printf("a is 1\n");  
    else // 这个else与哪个if相关联?  
        printf("a is not greater than b\n");  
  
    return 0;  
}

在这个例子中,else 子句实际上与内层的 if (a == 1) 相关联,而不是与外层的 if (a > b) 相关联。这是因为编译器将 else 子句与最近的、尚未匹配的if语句关联起来。所以这个例子不会输出打印任何语句!

修正:使用大括号明确作用域

为了避免这个问题,应该使用大括号 {} 来明确每个 if 语句的作用域,从而确保 else 子句与正确的 if 语句相关联。

#include <stdio.h>  
  
int main() {  
    int a = 1, b = 2;  
  
    if (a > b) {  
        if (a == 1) {  
            printf("a is 1\n");  
        }  
    } else {  
        printf("a is not greater than b\n");  
    }  
  
    return 0;  
}

在这个修正后的例子中,外层的 if-else 结构被大括号明确限定,因此 else 子句现在与 if (a > b) 相关联。

2.5 注意事项

2.5.1 if 后面不要加分号

在 C 语言中,“如果”(即 if 语句)后面直接加分号(;)通常是不合逻辑的,并且会导致编译错误或者逻辑上的错误,具体取决于你的意图和代码上下文。

当你看到 if 后面紧跟一个分号时,这通常意味着 if 语句的条件部分之后没有跟随任何要执行的语句,或者开发者可能误将某个语句放在了if语句的外部。这种用法往往是无效的或者是一个错误。

错误用法示例:

if (x > 0); // 这里有一个分号,但没有跟随任何语句  
printf("x is positive\n"); // 这行代码将无条件执行,因为它不在if语句块内

在上面的例子中,printf 语句不会根据 x > 0 的条件来决定是否执行。因为 if 语句后有一个分号,它实际上是一个空的 if 语句,而 printf 语句总是在 if 语句之后无条件执行。

正确用法示例:

if (x > 0) {  
    printf("x is positive\n"); // 只有当x > 0时,这行代码才会执行  
}

在这个例子中,if 语句正确地包含了要执行的代码块(由大括号 {} 包围),并且该代码块内的语句仅当x > 0时才会执行。

2.5.2 省略 else

if-else 结构中的 else 部分是可以省略的。当你只关心某个条件为真时的情况,而不关心条件为假时的情况,或者条件为假时不需要执行任何操作时,就可以省略 else 部分。

省略 else 的 if 语句的基本形式如下:

if (condition) {  
    // 当condition为真时执行的代码  
}  
// else部分被省略了

这里是一个简单的示例,它只在变量 x 大于 0 时打印一条消息:

#include <stdio.h>  
  
int main() {  
    int x = 5;  
  
    if (x > 0) {  
        printf("x is positive\n");  
    }  
    // 没有else部分,所以x不大于0时不会执行任何操作  
  
    return 0;  
}

2.5.3 省略 {}

在 C 语言中,当 if 或 else 语句块内只有一条语句时,可以省略大括号 {}。这是为了简化代码和提高可读性(尽管在某些情况下,省略大括号可能会降低可读性,特别是当代码变得复杂或需要修改时)。

if (x > 0)  
    printf("x is positive\n");  
else  
    printf("x is not positive\n");

在这个例子中,if 和 else 语句块内都只有一条语句,因此大括号被省略了。编译器能够正确地理解每个条件对应的执行语句。

即使只有一条语句,也建议使用大括号 {} 来明确语句块的范围,这有助于避免未来的错误。

2.5.4 注意点

选择分支(if...else):

确保条件表达式的逻辑清晰准确,避免出现歧义或错误的判断。

  • 例如,不要写成类似 if (a = 5) 这样的错误形式,应该是 if (a == 5) 。

注意代码的缩进和格式,以使结构清晰易读。

多分支(if...else if...else):

按照条件的可能性和优先级合理安排分支的顺序,将最可能满足的条件放在前面。

  • 例如,如果一个数值在大多数情况下处于某个特定范围内,就应该先检查这个范围。

确保每个分支的条件是互斥的,避免出现重复判断或遗漏的情况。

例如,下面是一个错误的多分支示例:

int num = 10;
if (num > 5) {
    printf("大于 5\n");
} else if (num > 8) {  // 错误,因为如果 num 大于 8 必然大于 5,这与前面的分支逻辑冲突
    printf("大于 8\n");
} else {
    printf("小于等于 5\n");
}

而正确的应该是:

int num = 10;
if (num > 8) {
    printf("大于 8\n");
} else if (num > 5) {
    printf("大于 5 小于等于 8\n");
} else {
    printf("小于等于 5\n");
}

嵌套 if...else:

避免过度嵌套,以免代码变得复杂难以理解。如果嵌套层次过多,可能需要考虑重构代码。

同样要注意条件的准确性和逻辑的清晰性。

  • 例如,在内层的 if...else 中,要明确其与外层条件的关系。

对于复杂的嵌套结构,可以添加适当的注释来解释代码的意图。


3 while 循环

while 循环是 C 语言中的一种基本控制流语句,它实现了 “当型” 循环结构

这种循环结构的特点是:在执行循环体内的语句之前,首先会评估一个条件表达式的值。如果条件表达式的值为非0(即真),则执行循环体内的语句;执行完毕后,再次评估条件表达式的值,如果仍为真,则重复执行循环体内的语句,如此往复,直到条件表达式的值为0(即假)时,循环结束,程序继续执行while循环之后的代码。

3.1 一般形式

while (表达式) {  
    // 循环体(包含零条或多条语句)  
}
  • 表达式:这是每次循环开始前被评估的条件表达式。如果其值为真(非零),则执行循环体
  • 循环体:包含了一组将被重复执行的语句。这些语句在条件为真时执行。

3.2 流程特点

先判断后执行:while循环首先检查条件表达式的值。如果条件为真,则执行循环体;如果为假,则跳过循环体,继续执行while循环之后的语句。

条件更新:为了避免死循环(即程序无限期地重复执行循环体),通常需要在循环体内部包含一些更新条件表达式的操作,以确保在某个时刻条件表达式的值会变为假,从而结束循环。

  1. 程序首先检查 while 循环的条件表达式。
  2. 如果条件为真(即,条件表达式的结果是非零值),则执行循环体内的语句。
  3. 完成循环体内的所有语句后,程序再次回到步骤1,重新检查条件表达式。
  4. 如果条件仍然为真,则再次执行循环体。这个过程会一直重复,直到条件变为假为止。
  5. 一旦条件变为假,程序将跳过循环体的执行,并继续执行 while 循环之后的下一条语句。

示例:

在下面这个例子中,while 循环会重复执行,直到变量 i 的值达到5(不再小于5),此时条件表达式 i < 5 变为假,循环结束。循环体内的 printf 语句用于打印变量i的当前值,而 i++ 语句则负责更新变量 i 的值,以确保循环能够正常结束。

#include <stdio.h>  
  
int main() {  
    int i = 0;  
    while (i < 5) { // 条件表达式  
        printf("%d\n", i); // 循环体  
        i++; // 更新条件表达式中的变量,确保循环能够在某个点结束 等价于 i += 1  
    }  
    return 0;  
}

输出结果如下所示:

 下面来看使用 while 语句计算1到100之间所有整数之和的累加例子,如下例所示:

#include <stdio.h>

int main() {
    int i=1,total=0;
    while( i <= 100 )//不能在 while 后面加分号
    {
        total += i;
        i++;//循环内要有使循环趋近于假的操作
    }
    printf("%d\n",total); // 5050
    return 0;
}

3.3 注意事项

3.3.1 while 后面不能加分号

在C语言中,如果在 while 语句的条件表达式后面直接加上一个分号(;),那么这个分号实际上被视为 while 循环的“空语句”体。这意味着 while 循环将无限地评估条件表达式,但由于循环体为空(即不执行任何操作),所以程序看起来像是没有做任何事情,但实际上它正忙于不断地检查条件表达式的值,从而导致了所谓的 “空循环” 或 “无限(死)循环”

错误的示例:

int i = 0;  
while (i < 5); { // 注意这里的分号  
    printf("%d\n", i);  
}  
// 这段代码会导致无限循环,因为 while 循环的“体”实际上是空的,  
// 而下面的花括号块则与 while 循环无关,会独立地执行一次(如果它不是位于函数之外的话),  
// 但这通常不是我们想要的结果。

正确的做法:

int i = 0;  
while (i < 5) {  
    printf("%d\n", i);  
    i++;  //循环内要有使循环趋近于假的操作
}  
// 这段代码正确地使用了while循环,循环体会在条件为真时执行。

3.3.2 使用花括号括起循环体

即使while循环体内只有一条语句,也建议使用花括号 {} 将其括起来。这有几个好处:

  • 清晰性:花括号明确地标出了循环体的开始结束,使得代码更加易于阅读和理解。
  • 可扩展性:随着程序的发展,你可能需要在循环体内添加更多的语句。如果一开始就使用了花括号,那么添加新语句时就不需要改变循环的结构。
  • 避免错误:如果不使用花括号,并且后来尝试在“单条语句”的循环体内添加更多语句,而没有意识到原来的语句已经被视为循环体,那么这些新添加的语句将不会被循环控制,这可能会导致难以发现的错误。

推荐的做法:

int i = 0;  
while (i < 5) {  
    printf("%d\n", i);  
    i++;  //循环内要有使循环趋近于假的操作
    // 如果将来需要添加更多语句,这里可以直接添加,而不需要改变循环的结构。  
}

4 do-while 循环

do-while 循环是C语言中另一种基本的循环控制结构,与 while 循环相似,但它有一个关键的区别:do-while 循环至少会执行一次循环体内的语句,即使条件表达式的值在第一次评估时就为假。这是因为 do-while 循环的控制结构是先执行循环体,然后再评估条件表达式。【先执行后判断

4.1 一般形式

do {  
    // 循环体(至少执行一次)  
} while (表达式);
  • 循环体:包含了一组在循环中重复执行的语句。在do-while 循环中,这些语句至少会被执行一次
  • 表达式:这是一个条件表达式,其值在每次循环体执行完毕后被评估。如果条件为真(非零),则循环继续;如果条件为假(零),则循环结束。

工作原理:

  1. 执行循环体内的语句。
  2. 评估条件表达式的值。
  3. 如果条件为真,则返回步骤1并重复执行循环体。
  4. 如果条件为假,则退出循环,继续执行 do-while 循环之后的语句。

示例:

#include <stdio.h>  
  
int main() {  
    int i = 0;  
    do {  
        printf("%d\n", i);  
        i++;  
    } while (i < 5);  
    return 0;  
}

在这个例子中,do-while 循环会首先执行循环体内的语句,即打印变量 i 的当前值,并将 i 的值增加1。然后,它评估条件表达式 i < 5。由于初始时 i 的值为0,小于5,因此条件为真,循环继续执行。这个过程会一直重复,直到 i 的值达到5,条件表达式变为假,循环结束。

4.2 注意事项

与 while 循环不同,do-while 循环至少会执行一次循环体,即使条件表达式的初始值为假。

为了避免无限循环,必须在循环体内包含某种更新条件表达式的操作,以确保在某个时刻条件会变为假。

在某些情况下,当你知道循环体至少需要执行一次时,do-while 循环是更好的选择。然而,在大多数情况下,while 循环和 for 循环(特别是后者,因为它更灵活)是更常用的循环控制结构。


5 for 循环

C 语言中的 for 循环语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况,它完全可以代替 while 循环语句。

5.1 一般形式

for (初始化表达式; 循环条件表达式; 更新表达式) {  
    // 循环体  
}

初始化表达式:在循环开始前执行,通常用于初始化一个或多个循环控制变量它只执行一次

循环条件表达式:在每次循环开始前求值。如果表达式的结果为真(非零),则执行循环体;如果为假(零),则退出循环。这是决定是否继续循环的关键。

更新表达式:在每次循环体执行完毕后执行,通常用于更新或递增/递减循环控制变量

循环体:当循环条件为真时,重复执行的语句块。

5.2 执行过程

(1)初始化表达式执行

  • 在循环开始前,首先执行初始化表达式。这通常用于设置循环控制变量的初始值。此表达式只执行一次。

(2)求解循环条件表达式

  • 接下来,求解循环条件表达式的值。如果表达式的值为真(即非零),则执行接下来的步骤;如果表达式的值为假(即零),则直接跳过循环体,执行 for 循环之后的语句。

(3)执行循环体

  • 如果循环条件表达式的值为真,则执行循环体内的语句。循环体可以包含一条或多条语句,用于完成循环需要重复执行的任务。

(4)求解更新表达式

  • 执行完循环体后,求解更新表达式。这通常用于更新循环控制变量的值,为下一次循环迭代做准备。更新表达式执行完毕后,控制流回到第(2)步

(5)转回第(2)步继续执行

  • 控制流回到第(2)步,再次求解循环条件表达式的值。如果条件仍为真,则重复执行第(3)步和第(4)步;如果条件为假,则跳出循环。

(6)循环结束,执行for语句下面的语句

  • 当循环条件表达式的值变为假时,循环结束。此时,程序将执行 for 循环之后的语句。

示例1:

#include <stdio.h>  
  
int main() {  
    for (int i = 1; i <= 5; i++) {  
        printf("%d\n", i);  
    }  
    return 0;  
}

在上面这个例子中,i = 1 是初始化表达式,它设置循环控制变量 i 的初始值为1。i <= 5 是循环条件表达式,只要i的值小于或等于 5,循环就会继续。i++ 是更新表达式,它在每次循环迭代结束时将i的值增加1。循环体是 printf 语句,用于打印当前的 i 值。

示例2:

#include <stdio.h>

int main() {
    int sum = 0;
    for (int i = 1; i <= 100; i++) {
        sum += i;
    }
    printf("1 到 100 之间的所有整数之和为: %d\n", sum);
    return 0;
}

我们首先初始化一个变量 sum 为 0,然后通过 for 循环从 1 迭代到 100。在每次循环中,将当前的整数 i 累加到 sum 中。最后,打印出求和的结果。

5.3 省略写法

在C语言中,for 循环的初始化表达式、循环条件表达式和更新表达式都是可选的,但两个分号(;)必须保留以维持语法结构。

5.3.1 省略初始化表达式

当省略初始化表达式时,循环变量(如果有的话)需要在循环外部进行初始化。

int i = 0; // 外部初始化  
for (; i < 5; i++) {  
    printf("%d\n", i);  
}

这里,i 在for 循环外部被初始化为 0 ,循环条件检查 i 是否小于5,如果是,则执行循环体,并在每次迭代后通过更新表达式 i++ 来增加i的值。

5.3.2 省略循环条件表达式

如果省略循环条件表达式,那么循环将变成无限循环,除非在循环体内部有某种机制(如break语句)来跳出循环。

int i = 0;  
for (; ; i++) {  
    if (i >= 5) break; // 使用break语句来跳出循环  
    printf("%d\n", i);  
}

在这个例子中,由于循环条件表达式被省略了,所以循环会一直执行,直到遇到 break 语句。

5.3.3 省略更新表达式

当省略更新表达式时,循环控制变量的值不会在每次迭代后自动更新。这通常意味着需要在循环体内部手动更新循环控制变量的值,或者依赖于循环体内部的其他逻辑来确保循环能够正确终止。

int i = 0;  
for (; i < 5; ) {  
    printf("%d\n", i);  
    i++; // 手动更新循环控制变量  
}

在这个例子中,尽管更新表达式被省略了,但我们在循环体的末尾手动增加了i的值,以确保循环能够正确终止。

5.3.4 省略所有表达式

for (;;) {  
    // 死循环即无限循环,直到遇到break或其他跳出循环的语句  
}

这种形式的 fo r循环通常用于需要持续运行直到某个条件满足(并在循环体内检查该条件)的情况。

省略 for 循环中的表达式可以提供灵活性,但也需要开发者更加小心地管理循环的控制流程,以避免无限循环或意外的程序行为。在实际编程中,建议仅在确实需要时才省略这些表达式,并确保循环的逻辑是正确的。

建议都写上,直观明了~

5.4 注意事项

5.4.1 for后面不能加分号

如果你在 for 循环的圆括号之后直接加了一个分号(;),那么你就定义了一个空的循环体。这意味着循环体将不会包含任何代码,而更新表达式(如果有的话)仍然会在每次循环时执行

for (int i = 0; i < 10; i++) {  
    // 正确的循环体  
}  
  
// 错误的用法,循环体为空  
for (int i = 0; i < 10; i++); {  
    // 这段代码实际上不在for循环内  
    printf("%d\n", i); // 注意:这里i在循环结束后才可用,但在这个上下文中可能产生编译错误或未定义行为  
}  
  
// 更常见的错误可能是这样的  
for (int i = 0; i < 10; i++); // 空的for循环,但分号结束  
printf("%d\n", i); // 这段代码在for循环之后执行,i的值是10(如果循环条件正确)

5.4.2 循环条件的正确性

确保循环条件能够准确地控制循环的开始、结束和迭代次数,避免出现无限循环或过早结束循环的情况。

// 错误示例:循环条件错误导致无限循环
for (int i = 0; i < 10; i--) {
    // 循环体
}

6 三种循环的选择

6.1 for循环

适用情况:当你知道循环需要执行的确切次数时,for循环是最佳选择。它也适用于需要初始化变量、检查条件和更新变量的场景。

优点:for循环的结构清晰,将初始化、条件和更新表达式集中在一起,使得循环的逻辑一目了然。

使用建议:在大多数需要计数或迭代固定次数的情况下,使用for循环。

6.2 while循环

适用情况:当你不知道循环需要执行的确切次数,但有一个持续检查的条件时,while循环是合适的。

优点:while循环提供了更大的灵活性,因为它不需要在循环开始前初始化变量或在每次迭代后更新变量。

使用建议:在需要基于条件持续执行循环,且循环次数不确定或条件与循环控制变量的更新不直接相关时,使用while循环。

6.3 do-while循环

适用情况:do-while循环与while循环类似,但它至少会执行一次循环体,无论条件是否为真。

优点:确保循环体至少被执行一次,这在某些情况下是有用的,比如当你需要至少执行一次操作来初始化或检查某些条件时

使用建议:在需要至少执行一次循环体,然后基于条件决定是否继续执行时,使用do-while循环。

 for 循环的可读性要比 while 循环的好,所以能使用 for 循环时不要强制改为 while 循环。


continue 语句

C 语言中的 continue 语句是一种流程控制语句,它用于跳过当前循环迭代中 continue 语句之后的剩余代码,并立即开始下一次循环迭代(如果有的话)。这意味着continue语句仅影响它所在的循环的当前迭代,而不会影响循环的继续执行或退出。

continue语句可以用在for循环、while循环和do-while循环中,但不能用在函数外部或任何其他控制结构(如if语句)中。

7.1 语法及示例

continue;

使用场景:continue 语句通常用于在循环体中遇到某些特定条件时,跳过当前迭代中的剩余部分,直接开始下一次迭代。这可以用于忽略某些不需要处理的元素或情况。

示例:对1到100之间的所有奇数进行求和

#include <stdio.h>  
  
int main() {  
    int sum = 0; // 用于存储奇数和的变量  
    for (int i = 1; i <= 100; i++) {  
        if (i % 2 == 0) {  
            continue; // 如果i是偶数,则跳过本次循环的剩余部分  
        }  
        sum += i; // 如果是奇数,则将其加到sum上  
    }  
    printf("1到100之间的奇数和为: %d\n", sum);  //2500
  
    return 0;  
}

7.2 注意事项

continue 语句只能在循环体内使用!

在 while 和 do-while 循环中使用continue语句时,需要特别小心,以确保不会跳过更新循环条件或执行使循环趋近于结束的必要语句。如果这样做了,就可能导致无限循环或不符合预期的行为。

7.2.1 对于while循环

在while循环中,循环条件是在每次迭代之前检查的。如果 continue 语句跳过了更新循环控制变量的代码,并且循环条件没有在其他地方被更新为可能使循环结束的值,那么循环可能会无限进行下去。

示例(错误用法)

int i = 0;  
while (i < 10) {  
    if (i % 2 != 0) {  
        continue; // 跳过奇数  
    }  
    printf("%d ", i);  
    i++; // 确保循环条件有机会变为假  
}

正确的 while 循环示例:

int i = 0;  
while (i < 10) {  
    if (i % 2 != 0) {  
        i++;  //这里也要来一下,防止continue跳过了
        continue; // 跳过奇数  
    }  
    printf("%d ", i);  
    i++; // 确保循环条件有机会变为假  
}

7.2.2 对于do-while循环

在do-while循环中,循环体至少执行一次,然后检查循环条件。如果 continue 语句被用来跳过更新循环控制变量的代码,并且循环条件在循环体内没有在其他地方被更新为可能使循环结束的值,那么循环也可能继续执行,直到外部干预(如break语句或程序的其他部分)。

do-while循环的示例:

#include <stdio.h>

int main() {
    int i = 0;
    do {
        if (i % 2 != 0) {
            i++;
            continue; // 跳过奇数
        }
        printf("%d ", i);
        i++; // 确保循环条件有机会变为假
    } while (i < 10);
    return 0;
}

break 语句

C 语言中的 break 语句是一种流程控制语句,它用于立即退出它所在的循环(for、while、do-while)或 switch 语句。当执行到 break 语句时,程序会跳过当前循环体中break语句之后的所有语句(如果有的话),并且跳出循环或 switch 语句,继续执行循环或 switch 之后的语句。

8.1 语法及示例

break;

示例:程序从1开始累加,当累加的和大于2000时,结束 for 循环,并打印此时 total 的值和循环变量 i 的值。

#include <stdio.h>

int main() {
    int i = 1; // 循环变量初始化
    int total = 0; // 累加和初始化

    for (; i <= 1000; i++) { // 注意这里去掉了i的初始化,因为我们在循环外已经初始化了i
        total += i; // 累加
        if (total > 2000) { // 检查累加和是否大于2000
            break; // 如果是,则退出循环
        }
    }

    // 打印结果
    printf("当累加的和大于2000时,i的值为:%d\n", i);  // 63
    printf("此时,累加和total的值为:%d\n", total);  //2016

    return 0;
}

8.2 注意事项

8.2.1 只会跳出当前所在的最内层结构

在嵌套的循环或 switch 语句中使用 break 时,它只会跳出当前所在的最内层结构,而不是所有的嵌套结构。如果想要跳出多层嵌套,可能需要额外的逻辑控制。

for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 5; j++) {
        if (j == 3) {
            break;  // 只会跳出内层的 for 循环,而不是外层的
        }
    }
}

8.2.2 适用范围

break 通常用于 switch 语句和循环结构(如 for、while、do-while)中。在其他地方使用可能会导致语法错误或不符合预期的逻辑。

在switch语句中的使用(后期课程学习,这里先引入下)

在 switch 语句中,break 语句用于防止代码自动“落入”下一个 case 块。如果没有 break 语句,一旦某个 case 的条件满足,从该 case 开始到 switch 语句结束(或遇到下一个 break 语句)之间的所有 case 块都会被执行,这通常不是预期的行为。

#include <stdio.h>  
  
int main() {  
    char grade = 'B';  
    switch(grade) {  
        case 'A':  
            printf("Excellent!\n");  
            break;  
        case 'B':  
        case 'C':  
            printf("Well done\n");  
            break;  
        case 'D':  
            printf("You passed\n");  
            break;  
        case 'F':  
            printf("Better try again\n");  
            break;  
        default:  
            printf("Invalid grade\n");  
    }  
    return 0;  
}

9 小节判断题

1、关系表达式或者逻辑表达式最终的结果都是 1 或者 0 ?

A 正确         B 错误

答案:A

解释:正确的,这个需要记住。


2、if 可以单独使用,不一定非要有 else ?

A 正确         B 错误

答案:A

解释:if 判断可以单独使用,这个需要记住。


3、 else 可以单独使用,不一定非要有 if ?

A 正确         B 错误

答案:B

解释:else 必须和 if 配对使用,不可以单独存在,这是语法要求。


4、代码编写 int a=5; if(3<a<10) 这种编写方式是否正确 ?

A 正确         B 错误

答案:B

解释:在程序中是错误的。首先,无论 a 是大于 3 还是小于 3,对于 3<a 这个表达式只有 1 或 0 两种结果。由于 1 和 0 都是小于 10 的,所以无论 a 的值为多少,这个表达式的值始终为真,因此在判断变量 a 是否大于 3 且同时小于 10 时,要写成 a>3 && a<10 ,这才是正确的写法。


5、 while(i<10); 这条语句没有问题,程序可以正常运行?

A 正确         B 错误

答案:B

解释:当在 while 语句的小括号后面加分号后,会造成死循环。


6、for(:;) 语句可以这么写,把 3 个表达式都省略,只剩余两个分号?

A 正确         B 错误

答案:A

解释:for 语句中的两个分号是不可以省略的,其他的表达式都可以省略,但是我们一般不会省略表达式,因为 for 的 3 个表达式使用起来非常方便


7、continue 语句的作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行是否执行下一次循环的判断?

A 正确         B 错误

答案:A

解释:这是 continue 的作用,需要记住,在 while 循环中使用 continue 要小心, continue 之前要有让 while 循环判断趋近于假的操作,避免死循环。


8、 break 语句的作用是结束整个循环过程?

A 正确         B 错误

答案:A

解释: break 语句是结束整个循环,和 continue 的区别一定要清晰,理解可以再次看视频,通过我们视频里的实例清晰理解。


10 OJ 练习

10.1 课时4作业1

这道题主要是练习如何通过循环操作,将一个整型数逆置,我们判断逆置后的整型数如果和
最初的数相等,那么它就是对称数,如果不相等,就不是对称数。

#include <stdio.h>

int main() {
    // inputNumber : 用于存储输入的数字
    // reversedNumber : 用于存储反转后的数字,必须初始化,后需要对其做乘10处理
    // tempNumber : 临时存储输入的数字,用于后续比较
    int inputNumber,reversedNumber = 0, tempNumber;

    // 从用户处获取输入的数字
    scanf("%d", &inputNumber);
    // 先把输入的数据保护好
    tempNumber = inputNumber;

    // 这个循环用于将输入的数字反转
    while (inputNumber) {
        reversedNumber = reversedNumber * 10 + inputNumber % 10;  // 将当前数字的个位添加到反转数字中,并乘以 10 为下一位做准备
        inputNumber /= 10;  // 去除当前数字的个位
    }

    // 判断输入的数字是否与反转后的数字相等
    if (tempNumber == reversedNumber) {
        printf("yes");  // 是对称数,输出"yes"
    } else {
        printf("no");  // 不是对称数,输出"no"
    }

    return 0;
}

10.2 课时4作业2

这个题目主要考察的是 for 循环的使用。

#include <stdio.h>

int main() {
    int number,factorial = 1; // 初始化阶乘结果为1  

    // 读取用户输入的数
    scanf("%d", &number);

    // 使用for循环计算阶乘  
    for(int i = 1; i <= number; i++) {
        factorial *= i; // 累乘计算阶乘  
    }

    // 输出结果  
    printf("%d\n", factorial);

    return 0;
}

10.3 课时4作业3

这个题目考察的是多层循环的使用,有 4 种类型钞票,那么我们选择 4 层循环,只需在最
内层的循环判断钞票组合后的值为 100,就可以完美解决这个问题。注意控制每一层循环的
边界,不要过大,当然如果每个边界都写 40,在 OJ 也可以 AC。

10元纸币的数量不能为0(至少1张),且不能超过9张(否则总金额会超过100元)  。

5元纸币的数量也不能为0(至少1张),(100-10-2-1) / 5=17,最多17张。

2元纸币的数量也不能为0(至少1张),最多37张。

1元纸币的数量也不能为0(至少1张),最多37张。

所以,四层循环如下:

#include <stdio.h>

int main() {
    int counter = 0; // 用于计数满足条件的换法

    // 外层循环:10元纸币的数量,从1到9张
    for (int i = 1; i <= 9; ++i) {
        // 注释:10元纸币的数量不能为0(至少1张),且不能超过9张(否则总金额会超过100元)

        // 第二层循环:5元纸币的数量,从1到17张
        for (int j = 1; j <= 17; ++j) {
            // 注释:5元纸币的数量也不能为0(至少1张),(100-10-2-1)/5=17

            // 第三层循环:2元纸币的数量,从1到37张
            for (int k = 1; k <= 37; ++k) {
                // 注释:2元纸币的数量也不能为0(至少1张),最多37张

                // 第四层循环:1元纸币的数量,从1到37张
                for (int l = 1; l <= 37; ++l) {
                    // 注释:1元纸币的数量也不能为0(至少1张),最多37张
                    
                    // 检查当前组合是否满足总金额为100元和总张数为40张的条件
                    if (100 == i * 10 + j * 5 + k * 2 + l * 1 && i + j + k + l == 40) {
                        counter++; // 如果满足条件,则计数器加1
                    }
                }
            }
        }
    }

    // 输出满足条件的换法总数
    printf("%d\n", counter);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1935592.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SaaS的“大模型焦虑”

随着大模型技术的兴起&#xff0c;SaaS行业正面临前所未有的机遇与挑战。本文深入剖析了SaaS厂商在AI化升级过程中的’大模型焦虑’&#xff0c;并探讨了如何通过战略性的AI应用找到自信&#xff0c;实现产品与服务的转型升级&#xff0c;为SaaS行业的AI之路提供了宝贵的思考与…

JVM之运行时数据区(一):程序计数器+本地方法栈

JVM之运行时数据区&#xff08;一&#xff09;&#xff1a;程序计数器本地方法栈 1.运行时数据区概述2.程序计数器作用特点常见问题 3.本地方法接口本地方法本地接口 4.本地方法栈特点 1.运行时数据区概述 Java虚拟机定义了若干种程序运行期间会使用到的运行时数据区其中有一些…

昇思25天学习打卡营第30天 | MindNLP ChatGLM-6B StreamChat

今天是第30天&#xff0c;学习了MindNLP ChatGLM-6B StreamChat。 今天是参加打卡活动的最后一天&#xff0c;经过这些日子的测试&#xff0c;昇思MindSpore效果还是不错的。 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;具有62亿参数&#xff0c;基于 …

业务系统核心模块资料访问性能优化实战

随着业务系统的云化转型不断推进&#xff0c;业务量呈现显著增长&#xff0c;对业务系统的性能和资源管理提出了更高要求。在这样的背景下&#xff0c;实现系统资源使用与性能指标的均衡成为保障生产系统高效稳定运行的核心任务。 在性能优化的范畴内&#xff0c;核心业务系统对…

Linux 10:进程信号

信号示例&#xff1a; 用户输入命令,在Shell下启动一个前台进程&#xff1a; 用户按[CtrlC]&#xff0c;这个键盘输入产生一个硬件中断&#xff0c;被OS获取&#xff0c;解释成信号&#xff0c;发送给目标前台进程。前台进程因为收到信号&#xff0c;进而引起进程退出。 注意&…

2048小游戏,h5,纯前端

部分代码 //scorevar scoreSprite game.add.sprite(10, 10);var scoreGraphics game.add.graphics(0, 0);scoreGraphics.lineStyle(5, 0xA1C5C5);scoreGraphics.beginFill(0x308C8C);scoreGraphics.drawRoundedRect(0, 0, 70, 50, 10);scoreGraphics.endFill();scoreSprite.a…

端到端语音识别

端到端语音识别 一.端到端语音识别的动机 1.传统语音识别语言模型训练 2.传统语音识别缺点 流程复杂且繁琐&#xff1a; 传统的语音识别系统涉及的流程非常多且复杂&#xff0c;从数据准备、模型训练到最终的系统集成&#xff0c;每个步骤都需要仔细处理。入门门槛高&#x…

WEB前端07-DOM对象

DOM模型 1.DOM概念 文档对象模型属于BOM的一 部分&#xff0c;用于对BOM中的核心对象document进行操作&#xff0c;它是一种与平台、语言无关的接口&#xff0c;允许程序和脚本动态地访问或更新HTML、XML文档的内容、结构和样式&#xff0c;且提供了一系列的函数和对象来实现…

近几天,北京大学副校长、教务长王博亲自为藏族女孩送上北京大学首封录取通知书!

藏族女孩代吉永措收到了北京大学2024年首封本科录取通知书。她来自青海湟川中学&#xff0c;已被北京大学历史学科强基计划录取&#xff0c;即将就读于北京大学历史学系。北京大学副校长、教务长王博亲自为代吉永措送上了这份录取通知书&#xff0c;并与她亲切交流了未来的学习…

Linux介绍和文件管理

一Linux的起源 1.Unix Dennis Ritchie和Ken Thompson发明了C语言&#xff0c;而后写出了Unix的内核 2.Minix MINIX是一种基于微 内核架构的类UNIX计算机操作系统&#xff0c;由 Andrew S. Tanenbaum发明 3.Linux内核 芬兰赫尔辛基大学的研究生Linus Torvalds基于Gcc、 ba…

注册安全分析报告:OneApm

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

C语言 ——— 打印水仙花数

目录 何为水仙花数 题目要求 代码实现 何为水仙花数 “水仙花数”是指一个n位数&#xff0c;其各位数字的n次方之和等于该数本身 如&#xff1a;153 1^3 5^3 3^3&#xff0c;则153就是一个“水仙花数” 题目要求 求出0~100000的所有“水仙花数”并输出 代码实现 #i…

万字 AI 干货及感悟分享

最近一直在研究 AI Agent 在零代码平台中的应用, 特地研究并总结了一份AI学习的干货, 方便大家快速理解LLM, 并熟悉主流的AI大模型框架, 以及如何基于AI, 来改善我们传统的工作模式. 上面是本文的核心大纲, 接下来开始我的分享和总结. LLM介绍 1. LLM概念 大语言模型&#x…

【安当产品应用案例100集】001 — 基于UKEY的文件加密流转

随着企业信息化程度的不断提高&#xff0c;数据已成为企业最重要的资产之一。然而&#xff0c;数据泄露的风险也随之增加。数据泄露可能导致企业商业机密泄露、客户隐私泄露、经济损失以及法律诉讼等一系列严重后果。因此&#xff0c;保护数据安全已成为企业不可忽视的重要任务…

互联网行业的产品方向(二)

数字与策略产品 大数据时代&#xff0c;数据的价值越来越重要。大多数公司开始对内外全部数据进行管理与挖掘&#xff0c;将业务数据化&#xff0c;数据资产化&#xff0c;资产业务化&#xff0c;将数据产品赋能业务&#xff0c;通过数据驱动公司业务发展&#xff0c;支撑公司战…

3112. 访问消失节点的最少时间 Medium

给你一个二维数组 edges 表示一个 n 个点的无向图&#xff0c;其中 edges[i] [ui, vi, lengthi] 表示节点 ui 和节点 vi 之间有一条需要 lengthi 单位时间通过的无向边。 同时给你一个数组 disappear &#xff0c;其中 disappear[i] 表示节点 i 从图中消失的时间点&#xff0…

Linux-交换空间(Swap)管理

引入概念 在计算机中&#xff0c;硬盘的容量一般比内存大&#xff0c;内存&#xff08;4GB 8GB 16GB 32GB 64GB…&#xff09;&#xff0c;硬盘&#xff08;512GB 1T 2T…&#xff09;。 冯诺依曼的现代计算机结构体系里面的存储器就是内存 内存是一种易失性存储器&#xff0c…

如何在 PostgreSQL 中处理海量数据的存储和检索?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 如何在 PostgreSQL 中处理海量数据的存储和检索&#xff1f;一、优化表结构设计二、分区技术三、数据压…

二叉树的后序遍历(寻找重复的子树,序列化

class Solution {List<TreeNode> resnew LinkedList<>();Map<String,Integer> mapnew HashMap<>();//用于存储子树public List<TreeNode> findDuplicateSubtrees(TreeNode root) {String xfind(root);return res;}public String find(TreeNode r…

HZNUCTF2023中web相关题目

[HZNUCTF 2023 preliminary]guessguessguess 这道题目打不开了 [HZNUCTF 2023 preliminary]flask 这道题目考察SSTI倒序的模板注入&#xff0c;以及用env命令获得flag 看题目&#xff0c;猜测是SSTI模板注入&#xff0c;先输入{7*7},发现模板是倒序输入的 输入}}7*7{{返回77…