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

目录

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); // 5050return 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);  //2500return 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的初始化,因为我们在循环外已经初始化了itotal += i; // 累加if (total > 2000) { // 检查累加和是否大于2000break; // 如果是,则退出循环}}// 打印结果printf("当累加的和大于2000时,i的值为:%d\n", i);  // 63printf("此时,累加和total的值为:%d\n", total);  //2016return 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.rhkb.cn/news/379646.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

去中心化技术的变革力量:探索Web3的潜力

随着区块链技术的发展和应用&#xff0c;去中心化技术正成为数字世界中的一股强大变革力量。Web3作为去中心化应用的新兴范式&#xff0c;正在重新定义人们对于数据、互联网和价值交换的认知。本文将探索去中心化技术的基本概念、Web3的核心特征及其潜力应用&#xff0c;展示其…

Linux——远程连接服务器

sshd服务端 ssh客户端 ssh 服务配置 #ssh 服务安装包 openssh-server [rootserver1 ~] # vim /etc/ssh/sshd_config 17 . #Port 22 # 监听端口&#xff0c;默认监听 22 端口 【默认可修改】 18 . #AddressFamily any #IPV4 和 IPV6 协议家族用哪个&#xff0c; any 表示二者…

捷配总结的SMT工厂安全防静电规则

SMT工厂须熟记的安全防静电规则&#xff01; 安全对于我们非常重要&#xff0c;特别是我们这种SMT加工厂&#xff0c;通常我们所讲的安全是指人身安全。 但这里我们须树立一个较为全面的安全常识就是在强调人身安全的同时亦必须注意设备、产品的安全。 电气&#xff1a; 怎样预…

操作系统发展简史(Unix/Linux 篇 + DOS/Windows 篇)+ Mac 与 Microsoft 之风云争霸

操作系统发展简史&#xff08;Unix/Linux 篇&#xff09; 说到操作系统&#xff0c;大家都不会陌生。我们天天都在接触操作系统 —— 用台式机或笔记本电脑&#xff0c;使用的是 windows 和 macOS 系统&#xff1b;用手机、平板电脑&#xff0c;则是 android&#xff08;安卓&…

C++写一个线程池

C写一个线程池 文章目录 C写一个线程池设计思路测试数据的实现任务类的实现线程池类的实现线程池构造函数线程池入口函数队列中取任务添加任务函数线程池终止函数 源码 之前用C语言写了一个线程池&#xff0c;详情请见&#xff1a; C语言写一个线程池 这次换成C了&#xff01;…

云监控(华为) | 实训学习day2(10)

spring boot基于框架的实现 简单应用 - 用户数据显示 开发步骤 第一步&#xff1a;文件-----》新建---项目 第二步:弹出的对话框中,左侧选择maven,右侧不选任何内容. 第三步&#xff0c;选择maven后&#xff0c;下一步 第4步 &#xff1a;出现对话框中填写项目名称 第5步&…

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

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

无线物联网新时代,RFID拣货标签跟随潮流

拣选技术的演变历程&#xff0c;本质上是从人力操作向自动化、智能化转型的持续进程。近期&#xff0c;“货寻人”技术成为众多企业热烈追捧的对象&#xff0c;它可以根据企业的特定需求&#xff0c;从众多拣选方案中选出最优解。那么&#xff0c;在采用“货到人”拣选技术时&a…

服务器基础1

服务器基础复习01 1.环境部署 系统&#xff1a;华为欧拉系统 网络简单配置nmtui 因为华为欧拉系统密码需要复杂度 所以我们可以进入后更改密码 echo 123 | passwd --stdin root也可以 echo "root:123" | chpasswd2.关闭防火墙&#xff0c;禁用SElinux 首先先关…

开源防病毒工具--ClamAV

产品文档&#xff1a;简介 - ClamAV 文档 开源地址&#xff1a;Cisco-Talos/clamav&#xff1a;ClamAV - 文档在这里&#xff1a;https://docs.clamav.net (github.com) 一、引言 ClamAV&#xff08;Clam AntiVirus&#xff09;是一个开源的防病毒工具&#xff0c;广泛应用…

222.买卖股票的最佳时机(力扣)

代码解决 class Solution { public:int maxProfit(vector<int>& prices) {// 初始化最小买入价为第一个价格int min1 prices[0];// 初始化最大利润为0int max1 0;// 从第二天开始遍历价格数组for (int i 1; i < prices.size(); i) {// 计算当前价卖出的利润&a…

圣诺联合加入龙蜥社区,共筑数据安全长城

近日&#xff0c;河北圣诺联合科技有限公司&#xff08;以下简称“圣诺联合”&#xff09;签署了 CLA&#xff08;Contributor License Agreement&#xff0c;贡献者许可协议&#xff09;&#xff0c;正式加入龙蜥社区&#xff08;OpenAnolis&#xff09;。 圣诺联合成立于 20…

jvm常用密令、jvm性能优化、jvm性能检测、Java jstat密令使用、Java自带工具、Java jmap使用

1.jps是Java虚拟机的进程状态工具&#xff0c;用于列出正在运行的Java进程 jps命令的使用&#xff1a;cmd打开直接jps 1.1不带参数&#xff1a; jps 默认情况下&#xff0c;列出所有正在运行的 Java 进程的进程 ID 和主类名。 1.2 -l&#xff1a;显示完整的主类名或 JAR 文件…

nacos 适配瀚高数据库、ARM 架构

下载nacos源码&#xff1a; https://github.com/alibaba/nacos/tree/2.3.1 瀚高技术文档 1、修改pom.xml 根目录nacos-all > pom.xml<dependencyManagement><dependency><groupId>com.highgo</groupId><artifactId>HgdbJdbc</artifactI…

免费的数字孪生平台助力产业创新,让新质生产力概念有据可依

关于新质生产力的概念&#xff0c;在如今传统企业现代化发展中被反复提及。 那到底什么是新质生产力&#xff1f;它与哪些行业存在联系&#xff0c;我们又该使用什么工具来加快新质生产力的发展呢&#xff1f;今天我将介绍一款为发展新质生产力而量身定做的数字孪生工具。 新…

0718,TCP协议,三次握手,四次挥手

目录 上课喵&#xff1a; TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;的状态迁移图 TCP连接的状态迁移图 状态迁移说明&#xff1a; 注意&#xff1a; big_htonl.c 字节序转换 addr.c IP地址的转换 作业喵&#xff1a; …

人工智能与算力:推动各行业变革的关键力量

随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;算力需求也在不断增加。算力&#xff0c;即计算能力&#xff0c;已经成为数字经济时代的核心资源之一。从科学研究到制造业&#xff0c;从医疗健康到教育&#xff0c;各行各业都在通过提升算力来推动自身的数…

基于springboot新生宿舍管理系统

系统背景 在当今高等教育日益普及的时代背景下&#xff0c;高校作为知识传播与创新的重要基地&#xff0c;其基础设施的智能化管理显得尤为重要。新生宿舍作为大学生活的起点&#xff0c;不仅是学生日常生活与学习的重要场所&#xff0c;也是培养学生独立生活能力和团队合作精神…

专题四:设计模式总览

前面三篇我们通过从一些零散的例子&#xff0c;和简单应用来模糊的感受了下设计模式在编程中的智慧&#xff0c;从现在开始正式进入设计模式介绍&#xff0c;本篇将从设计模式的7大原则、设计模式的三大类型、与23种设计模式的进行总结&#xff0c;和描述具体意义。 设计模式体…

Stateflow中的状态转换表

状态转换表是表达顺序模态逻辑的另一种方式。不要在Stateflow图表中以图形方式绘制状态和转换&#xff0c;而是使用状态转换表以表格格式表示模态逻辑。 使用状态转换表的好处包括&#xff1a; 易于对类列车状态机进行建模&#xff0c;其中模态逻辑涉及从一个状态到其邻居的转换…