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://xiahunao.cn/news/3250642.html

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

相关文章

查看Windows中监听的端口及其关联的服务

文章目录 I 查看Windows中监听的端口及其关联的服务进程id1.1 列出了所有监听的端口及其关联的服务1.2 查找特定的端口是否开放1.3 查看哪些服务正在监听这些端口II 根据进程id查看进程名称基于cmd窗口,查看程序运行端口状态(关联服务进程id)和关联的服务进程信息 I 查看Win…

LLM大模型实战项目--基于Stable Diffusion的电商平台虚拟试衣

本文详细讲解LLM大模型实战项目&#xff0c;基于Stable Diffusion的电商平台虚拟试衣 一、项目介绍 二、阿里PAI平台介绍 三、阿里云注册及开通PAI 四、PAI_DSW环境搭建 五、SDLORA模型微调 一、项目介绍 AI虚拟试衣是一种创新的技术&#xff0c;利用人工智能和计算机视觉技…

MacBook电脑远程连接Linux系统的服务器方法

一、问题简介 Windows 操作系统的电脑可使用Xshell等功能强大的远程连接软件。通过连接软件&#xff0c;用户可以在一台电脑上访问并控制另一台远程计算机。这对于远程技术支持、远程办公等场景非常有用。但是MacBook电脑的macOS无法使用Xshell。 在Mac上远程连接到Windows服…

Golang | Leetcode Golang题解之第238题除自身以外数组的乘积

题目&#xff1a; 题解&#xff1a; func productExceptSelf(nums []int) []int {length : len(nums)// L 和 R 分别表示左右两侧的乘积列表L, R, answer : make([]int, length), make([]int, length), make([]int, length)// L[i] 为索引 i 左侧所有元素的乘积// 对于索引为 …

Java(二十二)---队列

文章目录 前言1.队列(Queue)的概念2.Queue的使用3.队列的模拟实现4.循环队列5.双端队列6.面试题[1. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/description/)[2. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/de…

django中日志模块logging的配置和使用

一、文件的配置 settings.py文件中添加LOGGING块的配置&#xff0c;配置如下 # 日志记录 LOGGING {"version": 1,"disable_existing_loggers": False, # 用于确定在应用新的日志配置时是否禁用之前配置的日志器# 格式器"formatters": {"v…

自动化测试中如何应对网页弹窗的挑战!

在自动化测试中&#xff0c;网页弹窗的出现常常成为测试流程中的一个难点。无论是警告框、确认框、提示框&#xff0c;还是更复杂的模态对话框&#xff0c;都可能中断测试脚本的正常执行&#xff0c;导致测试结果的不确定性。本文将探讨几种有效的方法来应对网页弹窗的挑战&…

Android 视频亮度图标

源码 import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View;import androidx.annotation.Nullable;public class VideoBrightness …

优雅的软件工程师

今天写算法的时候、通过两道题深深意识到了&#xff0c;什么是优雅的代码&#xff08;应该说不按套路出牌的代码&#xff09; 我被折服了 第一个就是141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 判断换环状链表 我的思路就是用快慢指针判断&#xff0c;非常平平无…

SAP MR21 和 MR22 区别

MR21和MR22用来调整库存金额的话&#xff0c;两者之间有什么区别呢 一个是直接修改金额 一个是在原来的基础上进行加减。 MR21改的是单个物料的价格。 MR22改的是库存总价值。 MR**是不能改标准价格的&#xff0c;即使改了也到PRD去了&#xff0c;只能改移动平均价 MR21 : 商品…

HTTP协议、Wireshark抓包工具、json解析、天气爬虫

HTTP超文本传输协议 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;&#xff1a; 全称超文本传输协议&#xff0c;是用于从万维网&#xff08;WWW:World Wide Web &#xff09;服务器传输超文本到本地浏览器的传送协议。 HTTP 协议的重要特点&#xff1a; 一发一收…

简过网:备考25年国考的朋友,你的时间规划做好了吗?

备考25年国考的朋友&#xff0c;你的时间规划做好了吗&#xff1f; 根据以往考试时间&#xff0c;我们先预测一下25年的国考时间&#xff1a; 国考报名&#xff1a;24年10月中旬 国考笔试&#xff1a;24年11月底 省考报名&#xff1a;25年1-2月 省考笔试&#xff1a;25年3…

AnalyticsCloud 分析云 任意文件读取漏洞复现

0x01 产品简介 AnalyticsCloud 分析云集成了先进的数据分析技术和工具&#xff0c;能够处理来自各种数据源的数据&#xff0c;包括云数据、本地数据、传统数据和大数据等。它提供了从数据收集、整理、分析到应用的全链路解决方案&#xff0c;帮助企业更好地理解和利用数据&…

处理.git文件夹过大出现臃肿问题

1、问题背景 在软件开发过程中&#xff0c;版本控制是一个至关重要的环节。Git 作为一种流行的分布式版本控制系统&#xff0c;被广泛应用于各种项目中。然而&#xff0c;近期我们发现在进行项目发版时&#xff0c;Git 克隆项目的时间显著增加&#xff0c;严重影响了发版的效率…

深入理解Java并发编程:从synchronized到Lock的演进

目录 引言 一、synchronized关键字基础 二、Lock接口及其实现 三、ReentrantLock实战 1. 原子类&#xff08;Atomic Classes&#xff09; 2. 并发集合&#xff08;Concurrent Collections&#xff09; 3. 线程池&#xff08;ThreadPool&#xff09; 4. 并发工具类&…

四川赤橙宏海商务信息咨询有限公司真实可靠吗?

在当今数字化浪潮中&#xff0c;电商行业正以前所未有的速度蓬勃发展&#xff0c;而抖音作为短视频领域的佼佼者&#xff0c;其电商服务更是异军突起&#xff0c;成为众多商家争相入驻的新蓝海。四川赤橙宏海商务信息咨询有限公司&#xff0c;正是这一领域的佼佼者&#xff0c;…

【Git标签管理】理解标签 | 创建标签 | 查看标签 | 删除标签 | 推送标签

目录 1.理解标签 2.创建标签 3.查看标签 4.删除本地仓库的标签 5.推送标签 6.删除远程仓库的标签 1.理解标签 Git提供一个打标签的功能tag&#xff0c;对某一次事务/提交的表示&#xff08;作用/意义&#xff09;。标签 tag &#xff0c;可以简单的理解为是对某次 comm…

Python调用搜索引擎Meilisearch

文章目录 简介安装初试参考文献 简介 Meilisearch 是一个 Rust 语言编写的开源搜索引擎&#xff0c;用于快速构建全文搜索。2018 年发布&#xff0c;支持中文。 特点&#xff1a; 速度至上&#xff1a;50 毫秒返回结果。相关性优先&#xff1a;最相关的结果排在前面开发者友好…

request.getParameter()与request.getAttribute()的区别

request.getParameter&#xff08;&#xff09;与request.getAttribute&#xff08;&#xff09;的区别 1、数据来源2、使用范围3、数据类型4、使用场景 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1、数据来源 getParameter()&#xf…

C#数字医学影像系统(RIS/PACS)源码,Oracle数据库,C/S架构,运行稳定

数字医学影像系统&#xff08;RIS/PACS&#xff09;源码&#xff0c;三甲以下的医院都能满足。PACS 系统全套成品源码。 开发技术&#xff1a;C/S架构&#xff0c;C#开发语言&#xff0c;数据库服务器采用Oracle数据库。 医学影像存储与传输系统&#xff0c;融合了医学信息化…