在本文中,我们学习分支语句,循环语句和goto语句
一:什么是语句?
在C语言中,语句是一条完整的执行单元,它用于表达某种操作或执行特定的任务。C语言中的程序由一个个语句组成,每个语句都按照一定的顺序被执行。
C语言中常见的语句有以下几种:
- 表达式语句(Expression statement):最简单的语句形式,由一个表达式和以分号结尾组成。例如:
x = 10;
- 声明语句:用于在代码中声明一个或多个变量。例如:
int x = 10;
- 控制流语句:用于控制程序的执行流程,包括条件语句、循环语句和跳转语句等。例如:
if (x > 5) { ... }
、while (x < 10) { ... }
、break;
- 复合语句:也称为代码块,是由一对花括号括起来的语句序列。复合语句可以包含多个语句,并可以嵌套在其他语句中。例如:
{ int x = 10; printf("x = %d\n", x); }
- 空语句(Null statement):由一个分号组成,表示什么都不做。通常用于语法需要语句但实际不需要执行任何操作的情况下。例如:
;
注意,每个语句必须以分号结尾,分号表示语句的结束。编译器会按照语句的顺序逐一执行代码中的语句,以完成相应的操作和任务。
在c语言中,又九种控制语句,可分为以下三类:
- 条件判断语句也叫分支语句:if语句、switch语句;
- 循环执行语句:do while语句、while语句、for语句;
- 转向语句:break语句、goto语句、continue语句、return语句。
二:分支语句
在人生中,我们会面临着多种选择,不同的选择又有不同的结果,这就产生了分支
以上便是一个简单的双分支示意图,在c语言中我们通过if语句和switch语句来实现分支结构
2.1if语句
那if语句的语法结构是怎样的呢?
- 单分支:
if(表达式) { 语句; }
双分支:
if(表达式) { 语句1; } else { 语句2; }
多分支:
if(表达式1) { 语句1; } else if(表达式2) { 语句2; } else { 语句3; }
注意:else后面不带表达式
以下是这段代码的执行方式:
- 首先,会对表达式1进行求值判断。如果表达式1的结果为真(非零),则执行语句1,并跳过后续的 else if 和 else 部分。如果表达式1的结果为假(0),则继续执行下一步。
- 如果表达式1的结果为假(0),则会继续对表达式2进行求值判断。如果表达式2的结果为真(非零),则执行语句2,并跳过后续的 else 部分。如果表达式2的结果为假(0),则继续执行下一步。
- 如果前面的条件都不满足(即表达式1和表达式2的结果都为假),则执行语句3。
需要注意的是,条件语句的每个条件表达式都会按从上到下的顺序进行求值判断。一旦某个条件满足,则会执行相应的语句块,并跳过后续的条件和语句块。如果没有任何条件满足,则会执行最后的 else 语句块(如果有的话),或者整个条件语句结束。
2.2. 1 if - if - if 语句和 if - else if - else语句的区别
if-else if-else 和 if-if-if 语句有一些不同之处。让我们来看一下它们的区别。
- if - else if - else语句:
示例代码如下:
if (condition1) { // 执行代码块1 } else if (condition2) { // 执行代码块2 } else if (condition3) { // 执行代码块3 } else { // 执行默认代码块 }
- if-if-if语句:
示例代码如下:
if (condition1) { // 执行代码块1 } if (condition2) { // 执行代码块2 } if (condition3) { // 执行代码块3 }
- 执行逻辑不同:
- if-else if-else:当满足条件1时,执行代码块1,然后跳过后续的 else if 和 else 分支。如果条件1不满足,则继续检查下一个 else if 条件,依此类推如果没有任何条件满足,最后执行 else 分支(如果有)。
- if-if-if:每个 if 语句都会独立地进行条件判断和执行。不论前面的条件是否满足,都会检查并执行每个 if 语句。
- 执行次数不同:
- if-else if-else:只有一个分支会被执行。一旦条件满足,会执行相应代码块,并跳过后续分支。
- if-if-if:多个分支可以同时被执行。每个 if 语句都会独立地进行条件判断和执行。
综上所述,if-else if-else 和 if-if-if 在执行逻辑和执行次数上有所不同。我们需要根据具体的业务需求和逻辑,选择适合的条件语句结构来编写代码。
2. 2.2 悬空else问题
接下来看一段代码:
#include <stdio.h> int main() { int a = 0; int b = 2; if(a == 1) if(b == 2) printf("hehe\n"); else printf("haha\n"); return 0; }
这是一段有坑的代码:
一般人可能会认为,因为a == 1这个条件不满住,所以会执行else这个语句,打印 haha,其实不然,下面是代码的运行的结果:
可见打印的结果是hehe而不是haha,这是为什么呢?
主要原因是因为:
- else是和离它最近的if进行匹配的
所以这段代码的结果是打印hehe那么我们该怎么避免这种错误呢?我们可以适当的使用{}可以使代码的逻辑更加清楚。
以下是改进的代码
#include <stdio.h> int main() { int a = 0; int b = 2; if(a == 1) { if(b == 2) { printf("hehe\n"); } } else { printf("haha\n"); } return 0; }
这样 else 就是和第一个 if 进行匹配了,注意, else 和 if 一定要同等级,虽然第二个if在视觉上更近一些,但是第二个 if 和 else 的等级不一样。请注意辨别
2.2.3 if 条件内的判断技巧
请大家判断以下两个代码哪个更好
//代码1 int num = 1; if(num == 5) { printf("hehe\n"); }
//代码2 int num = 1; if(5 == num) { printf("hehe\n"); }
这两段代码作用相同,判断变量num
是否等于5,并打印出"hehe"。在这种情况下,两段代码效果相同
然而,代码4中的写法更好,将常量值放在等式的左侧。这种写法称为"常量左移"或"常量前置",是一种常见的编程习惯。使用常量左移的好处是可以避免在条件表达式时,错误地将=
写成==
,这种错误是比较常见的。将常量放在左侧时,如果不小心写成if(num = 5)
,编译器会报错,因为赋值操作返回的是赋值的值,所以num = 5的结果为真,执行if中的代码块,这样就和我们的初衷就背离了
所以,代码4的写法更好,可以提高代码的安全性和可读性。
2.2 switch语句
2.2.1 switch的语法
在 C 语言中,switch 语句用于根据某个表达式的值选择执行不同的代码块。它的语法结构如下:
switch (expression) { case constant1: // 代码块1 break; case constant2: //代码块2 break; default: // 代码块3 }
其中 expression
是需要进行比较的表达式,可以是整数或字符类型。每个 case
后面的 constant
是一个常量,它会与 expression
进行比较。如果 expression
的值与某个 case
后面的 constant
相等,程序将执行对应的代码块。如果没有匹配到任何 case
,那么将执行 default
后面的代码块(如果有deault)。
在 switch 语句中,break 语句用于跳出 switch 语句。当程序执行完某个 case 的代码块后,如果没有 break 语句,程序将会继续执行下一个 case 的代码块,直到遇到 break 或者 switch 语句结束。这种不加 break 的情况被称为 “case 穿透”。
如果在某个 case 的代码块中不加 break,会导致程序继续执行下一个 case 的代码块,而不会进行比较。这可能是有意为之,也可能是错误。比如:
switch (value) { case 1: // 代码块 1 case 2: // 代码块 2 break; case 3: // 代码块 3 break; default: // 代码块 4 }
如果 value
的值为 1,那么将会执行 代码块 1、代码块 2 和 代码块3 和代码块4。因为在第一个 case 中没有使用 break,所以程序会继续向下执行。加入 break 语句可以控制代码的执行流程,避免出现不可预期的结果。
总结一下,switch 语句是根据表达式的值选择执行不同的代码块。通过在各个 case 中使用 break 语句可以控制代码的流程。如果没有使用 break,会导致 case 穿透,程序会继续执行下一个 case 的代码块。
2.2.2switch处理多分支和if语句处理多分支的区别
在c语言中,switch语句也是一种分支语句。常常用于多分支的情况。
例如我们需要写这样一个程序:
输入1,输出星期一
输入2,输出星期二
输入3,输出星期三
输入4,输出星期四
输入5,输出星期五
输入6,输出星期六
输入7,输出星期日
如果用 - if - else if - else 语句写的话应该是这样:
#include <stdio.h> int main() { int day; printf("请输入一个数字: "); scanf("%d", &day); if (day == 1) { printf("星期一\n"); } else if (day == 2) { printf("星期二\n"); } else if (day == 3) { printf("星期三\n"); } else if (day == 4) { printf("星期四\n"); } else if (day == 5) { printf("星期五\n"); } else if (day == 6) { printf("星期六\n"); } else if (day == 7) { printf("星期日\n"); } else { printf("输入无效,请输入一个介于1-7之间的数字。\n"); } return 0; }
c语言为我们提供了一个专门处理多分支的语句switch
用switch语句我们可以这样写:
#include <stdio.h> int main() { int day; printf("请输入一个数字代表星期几(1-7):"); scanf("%d", &day); switch(day) { case 1: printf("星期一\n"); break; case 2: printf("星期二\n"); break; case 3: printf("星期三\n"); break; case 4: printf("星期四\n"); break; case 5: printf("星期五\n"); break; case 6: printf("星期六\n"); break; case 7: printf("星期日\n"); break; default: printf("无效的输入\n"); } return 0; }
使用 switch 语句处理多分支和使用 if 语句处理多分支都可以实现相同的功能,但它们在某些方面有不同的优势。
以下是 switch 语句相对于 if 语句的一些优点:
- 代码可读性:当存在多个互斥的选项时,使用 switch 语句可以使代码更加简洁和可读。每个 case 独立地处理一个特定的情况,使代码结构清晰。
- 性能优化:在某些情况下,使用 switch 语句可以提高代码的执行效率。因为 switch 语句的实现方式使用了跳转表(jump table),可以直接根据表达式的值跳转到对应的分支,而不需要逐个检查每个条件。
- 代码可维护性:当需要添加或修改分支条件时,使用 switch 语句可以更方便地进行扩展和维护。只需要添加或修改相应的 case 分支即可,而不需要修改大量的 if 条件。
需要注意的是,switch 语句只能处理离散的值,比如整数类型或字符类型。它对于范围的处理能力有限,而 if 语句可以使用逻辑运算符来处理更复杂的条件。
总之,选择使用 switch 语句还是 if 语句取决于具体的业务需求,以及在代码的可读性、性能和可维护性之间做出权衡。
三:循环语句
在生活中,有些事情需要我们重复不断的去完成,比如说睡觉,洗澡,吃饭,学习,而在c语言中我们可以通过while循环 for循环和do while循环来重复执行某一段代码。
下面我们来一一介绍
3.1 while循环
在C语言中,while
循环是一种基本的循环结构,它允许我们根据给定的条件重复执行一段代码。while
循环的基本语法如下:
while (condition) { // 执行的代码块 }
当condition
条件为真(非零)时,循环中的代码块会被执行。执行完一次代码块后,会再次判断condition
条件是否为真,如果为真,则再次执行代码块,以此类推,直到condition
条件为假(零),才会退出循环。
使用while循环的时候注意以下几点:
- 循环条件:要确保循环条件最终能够变为假,否则会造成无限循环。
- 循环体:循环体中的代码块会被重复执行,因此要确保循环体中的代码能够正常运行,要有循环变量的更新:要确保循环中的变量会根据需要进行更新,以免陷入死循环或产生错误结果。
下面是一个使用while
循环的简单示例:
#include <stdio.h> int main() { int count = 0; while (count < 5) { printf("Count: %d\n", count); count++; // 更新循环变量 } return 0; }
在上述示例中,通过设置count
变量,循环执行5次。我们在代码块中每循环一次让count自增1,这样能够让条件最终变假,不会陷入死循环
3.2 for循环
在C语言中,for循环是一种用于重复执行代码块的循环结构。它允许我们指定循环变量的初始值、循环条件和每次循环后更新循环变量的操作。for循环的语法如下:
for (初始化表达式; 循环条件; 更新表达式) { // 循环体 }
for循环的作用是重复执行循环体,并允许我们对循环变量进行精确控制。我们可以使用它来实现一系列需要重复执行的任务
下面是一个简单的例子,展示了如何使用for循环计算1到10的和:
#include <stdio.h> int main() { int sum = 0; for (int i = 1; i <= 10; i++) { sum += i; } printf("Sum: %d\n", sum); return 0; }
在这个例子中,我们使用了三个重要的组成部分来控制循环的行为:
- 初始化表达式:我们将循环变量
i
设置为1,指定了循环的起始值。 - 循环条件:我们使用
i <= 10
作为循环条件,这意味着当i
小于等于10时循环继续执行,否则循环结束。 - 更新表达式:在每次循环结束后,我们使用
i++
将循环变量i
增加1,以便进行下一次迭代。
循环体部分中,我们将当前的 i
值添加到 sum
变量中,因此在每次循环迭代中,sum
的值会被更新。
最终,我们输出了 sum
的值,结果为1到10的和,即55。
使用for循环时需要注意的一些点包括:
- 每个组成部分之间使用分号进行分隔。
- 初始化表达式和更新表达式可以包含多个语句,以逗号分隔。
例如:
for (x = 0,y = 0; x < 2 && y< 5;++x,++y) { //代码块 }
- 循环条件为真时,便会执行循环体内的代码。
for(;;)是最简单的死循环,因为这个for循环没有判断条件,默认为真
3.3 break和continue
在C语言中,"break"和"continue"是控制循环的关键字。continue和break都可以用在 for、while、do-while 循环以及 switch 语句中。它们分别用于终止循环和跳过当前迭代,让程序按照特定的需求执行。
- break语句:
- 当break语句出现在循环体内部时,会立即终止该循环,并跳出循环外的下一条语句。
- break语句通常与条件语句(如if)结合使用,用于提前结束循环。
- break语句常用于遍历数组或者实现条件判断来终止循环。
以下是一个使用break语句的示例:
#include <stdio.h> int main() { int i; for (i = 1; i <= 10; i++) { if (i == 5) { break; } printf("%d ", i); } printf("Loop ended!\n"); return 0; }
输出:
1 2 3 4 Loop ended!
在上面的示例中,当i等于5时,break语句会立即终止循环,因此只输出了1、2、3和4。
- continue语句:
- 当continue语句出现在循环体内部时,会跳过当前迭代中continue之后的代码,并进行下一次迭代。
- continue语句用于提前结束当前迭代,但并不会终止整个循环。
以下是一个使用continue语句的示例:
#include <stdio.h> int main() { int i; for (i = 1; i <= 10; i++) { if (i == 5) { continue; } printf("%d ", i); } printf("Loop ended!\n"); return 0; }
输出:
1 2 3 4 6 7 8 9 10 Loop ended!
在上面的示例中,当i等于5时,continue语句会跳过当前迭代,而不执行后面的代码。因此,输出中没有数字5。
总结:
- break语句用于终止整个循环,并跳出循环外的下一条语句。
- continue语句用于跳过当前迭代中continue之后的代码,进行下一次迭代。
- break和continue语句通常与条件语句结合使用,以根据特定条件来控制循环的终止和跳过。
3.4for循环和while循环的对比
下面我们来看一段代码:
#include <stdio.h> int main() { int i = 0; for(i=1; i<=10; i++) { if(i == 5) break; printf("%d ",i); } return 0; }
//代码2 #include <stdio.h> int main() { int count = 0; while (count < 5) { printf("Count: %d\n", count); count++; // 更新循环变量 } return 0; }
在for循环中,循环变量的初始化、条件判断和更新都在一个地方进行,使得代码更加集中、简洁。而while循环的三个部分可能比较偏远,这样查找和修改循环变量就不够集中和方便
3.5do while循环
当你想要先执行一次循环体,然后再根据条件判断是否继续执行循环时,可以使用C语言中的do-while循环。
do-while循环的基本语法如下:
do { // 循环体 } while (条件);
do-while循环的执行过程是这样的:首先执行循环体,然后在循环体执行完之后再进行条件判断。如果条件满足,则继续执行循环体,否则结束循环。因此,do-while循环保证至少执行一次循环体。
do-while 循环和 for 循环 while 循环没什么不同,都是重复做一件事情,只是 do-while ,循环会先执行一次代码块中的代码,仅此而已,因为使用场景有限,所以不是很经常使用
四:goto 语句
在C语言中,goto
语句可以用来无条件地转移到程序中的某个标签(label)处执行代码。它的基本语法如下:
goto label; // ... label://冒号 // 代码块
其中,label
是由用户自定义的标签,用来标识需要跳转到的位置。在执行到goto
语句时,程序将会跳转到label
所在的位置,继续执行标签处的代码块。
使用goto语句的时候需要注意以下几点:
- 合理使用
goto
语句:由于goto
语句具有无条件跳转的特性,过度使用它可能导致程序结构混乱,难以理解和维护。因此,应谨慎使用goto
语句,避免滥用。 - 避免跳过变量初始化:当使用
goto
语句跳转到某个标签时,应确保经过的代码路径中的变量已经被正确初始化。否则,可能会导致未定义的行为。 - 避免跨越变量作用域:在使用
goto
语句时,应注意不要跨越变量的作用域。否则,可能会导致变量不可见或者访问非法内存的问题。 - 避免嵌套过多的
goto
语句:嵌套过多的goto
语句会使代码变得复杂和难以理解。在逻辑结构清晰的情况下,尽量避免使用嵌套的goto
语句。
以下是goto语句的使用示例
使用goto语句来实现循环打印1-10的代码:
#include <stdio.h> int main() { int i = 1; loop: printf("%d ", i); i++; if (i <= 10) { goto loop; // 跳转到loop标签处继续循环 } return 0; }
在上述代码中,我们使用了一个标签loop来表示循环的起始点。通过使用goto语句,我们在每次打印完数字后跳转到loop标签处,从而实现了循环打印1-10的效果。
注意:标记和goto无先后顺序
需要注意的是,尽管goto语句在某些特定情况下可能很方便,但它容易导致代码的可读性和维护性降低。因此,在实际开发中应尽量避免过多地使用goto语句,尽量使用其他更结构化的语句(如for循环、while循环)来实现循环逻辑。