C_语句

C_语句

在C语言中,语句可以分为以下几种类型:

  1. 标签语句:可以通过标签来标记一个语句。C语言中有三种类型的标签:简单标识符后跟冒号(用于goto语句的目标)、casedefault标签(用于switch语句中)。
  2. 复合语句:也称为块语句,是将多个语句和声明用大括号{ }括起来,形成一个单独的语句块。函数体也是一种复合语句。
  3. 表达式语句:由一个可选的表达式后跟分号;构成。如果存在表达式,则该语句可能有值。没有表达式的情况下,语句通常被称为空语句。
  4. 选择语句:包括if语句和switch语句,用于根据表达式的值选择执行不同的语句块。
  5. 迭代语句:包括whiledo-whilefor语句,用于重复执行某段代码直到满足特定条件。
  6. 跳转语句:包括gotobreakcontinuereturn语句,用于无条件地改变程序的控制流。

选择语句

布尔值

最初的c语言缺少布尔类型。在 C99 中,定义了 _Bool 类型, _Bool 类型的变量只能赋值为 01。往 _Bool 类型中存储非零值,会导致该变量赋值为 1

1
_Bool flag = 5; /* flag is assigned 1 */

C99 中还提供了一个新的头文件 stdbool.h,该头文件定义了 bool 宏,用它来表示_Bool ;该头文件还定义了 truefalse 两个宏,它们分别代表 10

1
2
3
#include <stdbool.h>
...
bool flag = true;

if语句

if语句:

1
if (expr) {statement;}

if 语句 else 子句:

1
2
3
4
if (expr)
{statement;}
else
{statement;}

级联式 if 语句:

1
2
3
4
5
6
7
8
9
if (expr)
   statement
else if (expr)
   statement
...
else if (expr)
   statement
else
   statement

悬空 else 问题:

else 子句应该属于离它最近的,且还没有和其它 else 匹配的 if 语句。为了使 else 子句属于外层的 if 语句,需用花括号将内层的 if 语句括起:

1
2
3
4
5
6
7
if (y != 0) 
{
if (x != 0)
result = x / y;
}
else
printf("Error: y is equal to 0\n");

条件表达式

C 语言的一种特殊的运算符——条件运算符,条件运算符由 ?: 组成,其格式如下:

1
expr1 ? expr2 : expr3

条件运算符是 C 语言中唯一一个三目运算符

条件表达式的求值步骤是:首先计算 expr1 的值,如果该值不为 0,则计算 expr2 的值,并且把 expr2 的值当作整个表达式的值;如果 expr1 的值为 0,那么计算 expr3的值,并把 expr3 的值当作整个表达式的值。

1
2
3
4
5
6
int i, j, k;
i = 1;
j = 2;
k = i > j ? i : j;
k = i > j ? i++ : j++;
k = (i >= 0 ? i : 0) + j;

最后一条语句的圆括号是必须的,三目运算符的优先级只比赋值运算符的优先级高一点。

switch语句

switch 语句的执行速度比 if 语句快。 switch 语句比级联式 if 语句更容易阅读。

switch 语句:

1
2
3
4
5
6
7
8
9
switch (expr) {
case constant-expr:
statements;
...
case constant-expr:
statements;
default:
statements;
}

switch 语句的组成成分:

控制表达式switch 后边表达式的值必须是整数类型。字符类型也当作整数来处理, switch 语句也可以对字符类型进行判定。但不能判定浮点数字符串(浮点数存在精度问题,字符串会增加编译器的实现复杂性)。

分支标号case 后边必须跟常量表达式(在编译期间求值的表达式),并且常量表达式的值必须是整数、字符类型。

语句:每个case标签后可以跟任意数量的语句(不需要用大括号括起来),通常每组语句的最后会有一个break语句,用于跳出switch语句的执行。

Tips:

  1. C 语言不允许有重复的分支标号,但对分支的顺序没有要求,特别是 default 分支不一定要放到最后。
  2. switch 语句不要求一定要有 default 分支。
  3. default 不存在,而且控制表达式的值和任何一个分支标号都不匹配,控制会直接传递给 switch 后面的语句。

case穿透:一个分支的最后没有 break 语句,控制会从一个分支继续到下一个分支。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
switch (grade) {
case 4:
printf("Excellent ");
   break;
case 3:
printf("Good ");
case 2:
printf("Average ");
case 1:
printf("Poor ");
case 0:
printf("Failing ");
default:
printf("Illegal grade");
}

如果grade的值为 3,会显示:Good Average Poor Illegal grade

循环语句

每个循环语句都有一个控制表达式。每次执行循环体时,都要对控制表达式求值。如果表达式为真,那么继续执行循环语句;否则执行循环语句的下一条语句。

while语句

while 语句:控制表达式是在每次执行循环体之前进行判定。

1
2
while (expr) 
{statement}

无限循环:控制表达式 expr 的值始终非零, while 语句将永远执行下去。

do...while语句

do...while 语句:控制表达式是在每次执行完循环体之后进行判定。

1
2
3
do 
{statement}
while (expr);

do...while 语句和 while 语句的唯一区别:do...while 语句的循环体至少会执行一次,而 while 语句在控制表达式的值初始为 0 时,一次都不会执行。

for语句

for 语句:非常适合递增或递减计数变量的循环

1
2
for (expr1; expr2; expr3) 
{statement}
  1. expr1 是循环开始执行前的初始化步骤,只执行一次
  2. expr2 是控制循环的控制表达式
  3. expr3 是每次循环中最后被执行的一个操作。

省略 for 语句中的的表达式:

  1. 省略 expr1 ,在执行循环前没有初始化的操作。
  2. 省略 expr2expr2的值默认为真,无限循环。
  3. 省略 expr3,循环体需要确保 expr2 的值最终会变成 0
  4. 同时省略 expr1expr3 时, for 语句和 while 语句一样。

for 语句的第一个表达式可以替换为声明一个或多个用于循环的变量:

1
2
for (int i = 0, j = 0; i < n; i++)
  ...

变量 i 不需要在该语句前进行声明。如果变量 i 在之前已经进行了声明,这个语句将创建一个新的 i,且该变量只能在循环内使用。( for 语句声明的变量在循环外是不可见。)

逗号表达式

逗号表达式允许在一个语句中同时执行多个表达式,并以逗号分隔。逗号表达式的值是最后一个表达式的值。逗号表达式的格式如下:

1
expr1, expr2, ..., exprn

逗号表达式的求值:逗号表达式是左结合的,逗号表达式从左到右依次执行,每个表达式都会被依次计算并丢弃其值,最终的结果是最后一个表达式的值。

作用

  • for循环中初始化和更新多个变量。
  • 在一个语句中执行多个操作,例如执行一系列函数调用或变量赋值,并只保留最后一个表达式的值。

跳转语句

C语言提供了四种跳转语句:breakcontinuegotoreturn

break 语句

break 可以跳出 switch , while , do...whilefor 语句。当语句嵌套时,break 只能跳出包含 break 语句的最内层嵌套。

1
2
3
4
5
while (...) {
   switch (...) {
       break;
  }
}

continue 语句

continue语句与break语句对比:

  1. break 语句会把控制转移到整个循环的后面,而 continue 会将控制转移到循环体的末尾

  2. break 语句会跳出循环,而 continue 语句仍然留在循环体内。

  3. break 语句可以用于 switch 语句和循环,而continue 只能用于循环。

  4. for循环中,执行continue后会跳到循环的更新表达式;在whiledo-while循环中,执行continue后会跳到循环的条件判断。

    1
    2
    3
    4
    5
    for (int i = 0; i < 5; i++) {
    if (i == 2) continue;
    printf("i=%d\n", i);
    }
    // 输出:i=0 i=1 i=3 i=4

goto 语句

goto语句可以跳转到函数中任何有标号的语句处。唯一限制只能在函数内进行跳转。

标号是放置在语句开始处的标识符:

1
2
identifier: 
statement

goto语句的格式如下:

1
goto identifier;

使用goto可以实现从深层嵌套结构中跳出,但过多使用会使程序结构混乱,不易理解和维护。

1
2
3
4
5
if (error) goto error_handler;
// 正常执行的代码
return;
error_handler:
// 错误处理代码

return 语句

return语句用于结束函数的执行,并将控制权返回给函数的调用者。如果函数声明了返回类型,return语句还可以返回一个值。

return可以在函数的任何位置使用,一旦执行,函数的剩余部分将不会被执行。

1
2
3
int add(int a, int b) {
return a + b;
}