C 语言流程控制

C 语言的程序是顺序执行,即先执行前面的语句,再执行后面的语句。开发者如果想要控制程序执行的流程,就必须使用流程控制的语法结构,主要是条件执行和循环执行。

1.if 语句

if语句用于条件判断,满足条件时,就执行指定的语句。

objectivec 复制代码
if (expression) statement

上面式子中,表达式expression为真(值不为0)时,就执行statement语句。

if后面的判断条件expression外面必须有圆括号,否则会报错。语句体部分statement可以是一个语句,也可以是放在大括号里面的复合语句。下面是一个例子。

objectivec 复制代码
if (x == 10) printf("x is 10");

上面示例中,当变量x10时,就会输出一行文字。对于只有一个语句的语句体,语句部分通常另起一行。

objectivec 复制代码
if (x == 10)
  printf("x is 10\n");

如果有多条语句,就需要把它们放在大括号里面,组成一个复合语句。

objectivec 复制代码
if (line_num == MAX_LINES) {
  line_num = 0;
  page_num++;
}

if语句可以带有else分支,指定条件不成立时(表达式expression的值为0),所要执行的代码。

objectivec 复制代码
if (expression) statement
else statement

下面是一个例子。

objectivec 复制代码
if (i > j)
  max = i;
else
  max = j;

如果else的语句部分多于一行,同样可以把它们放在大括号里面。

else可以与另一个if语句连用,构成多重判断。

objectivec 复制代码
if (expression)
  statement
else if (expression)
  statement
...
else if (expression)
  statement
else
  statement

如果有多个ifelse,可以记住这样一条规则,else总是跟最接近的if匹配。

objectivec 复制代码
if (number > 6)
  if (number < 12)
    printf("The number is more than 6, less than 12.\n");
else
  printf("It is wrong number.\n");

上面示例中,else部分匹配最近的if(即number < 12),所以如果number等于6,就不会执行else的部分。

这样很容易出错,为了提供代码的可读性,建议使用大括号,明确else匹配哪一个if

objectivec 复制代码
if (number > 6) {
  if (number < 12) {
    printf("The number is more than 6, less than 12.\n");
  }
} else {
  printf("It is wrong number.\n");
}

上面示例中,使用了大括号,就可以清晰地看出else匹配外层的if

2.三元运算符 ?:

C 语言有一个三元表达式?:,可以用作if...else的简写形式。

objectivec 复制代码
<expression1> ? <expression2> : <expression3>

这个操作符的含义是,表达式expression1如果为true(非0值),就执行expression2,否则执行expression3

下面是一个例子,返回两个值之中的较大值。

objectivec 复制代码
(i > j) ? i : j;

上面的代码等同于下面的if语句。

objectivec 复制代码
if (i > j)
  return i;
else
  return j;

3.switch 语句

switch 语句是一种特殊形式的 if...else 结构,用于判断条件有多个结果的情况。它把多重的else if改成更易用、可读性更好的形式。

objectivec 复制代码
switch (expression) {
  case value1: statement
  case value2: statement
  default: statement
}

上面代码中,根据表达式expression不同的值,执行相应的case分支。如果找不到对应的值,就执行default分支。

下面是一个例子。

objectivec 复制代码
switch (grade) {
  case 0:
    printf("False");
    break;
  case 1:
    printf("True");
    break;
  default:
    printf("Illegal");
}

上面示例中,根据变量grade不同的值,会执行不同的case分支。如果等于0,执行case 0的部分;如果等于1,执行case 1的部分;否则,执行default的部分。default表示处理以上所有case都不匹配的情况。

每个case语句体的结尾,都应该有一个break语句,作用是跳出整个switch结构,不再往下执行。如果缺少break,就会导致继续执行下一个casedefault分支。

objectivec 复制代码
switch (grade) {
  case 0:
    printf("False");
  case 1:
    printf("True");
    break;
  default:
    printf("Illegal");
}

上面示例中,case 0的部分没有break语句,导致这个分支执行完以后,不会跳出switch结构,继续执行case 1分支。

利用这个特点,如果多个case分支对应同样的语句体,可以写成下面这样。

objectivec 复制代码
switch (grade) {
  case 0:
  case 1:
    printf("True");
    break;
  default:
    printf("Illegal");
}

上面示例中,case 0分支没有任何语句,导致case 0case 1都会执行同样的语句体。

case后面的语句体,不用放在大括号里面,这也是为什么需要break的原因。

default分支用来处理前面的 case 都不匹配的情况,最好放在所有 case 的后面,这样就不用写break语句。这个分支是可选的,如果没有该分支,遇到所有的 case 都不匹配的情况,就会直接跳出整个 switch 代码块。

4.while 语句

while语句用于循环结构,满足条件时,不断执行循环体。

objectivec 复制代码
while (expression)
  statement

上面代码中,如果表达式expression为非零值(表示真),就会执行statement语句,然后再次判断expression是否为零;如果expression为零(表示伪)就跳出循环,不再执行循环体。

objectivec 复制代码
while (i < n)
  i = i + 2;

上面示例中,只要i小于ni就会不断增加2。

如果循环体有多个语句,就需要使用大括号将这些语句组合在一起。

objectivec 复制代码
while (expression) {
  statement;
  statement;
}

下面是一个例子。

objectivec 复制代码
i = 0;

while (i < 10) {
  printf("i is now %d!\n", i);
  i++;
}

printf("All done!\n");

上面代码中,循环体会执行10次,每次将i增加1,直到等于10才退出循环。

只要条件为真,while会产生无限循环。下面是一种常见的无限循环的写法。

objectivec 复制代码
while (1) {
  // ...
}

上面的示例虽然是无限循环,但是循环体内部可以用break语句跳出循环。

5.do...while 结构

do...while结构是while的变体,它会先执行一次循环体,然后再判断是否满足条件。如果满足的话,就继续执行循环体,否则跳出循环。

objectivec 复制代码
do statement
while (expression);

上面代码中,不管条件expression是否成立,循环体statement至少会执行一次。每次statement执行完毕,就会判断一次expression,决定是否结束循环。

objectivec 复制代码
i = 10;

do --i;
while (i > 0);

上面示例中,变量i先减去1,再判断是否大于0。如果大于0,就继续减去1,直到i等于0为止。

如果循环部分有多条语句,就需要放在大括号里面。

objectivec 复制代码
i = 10;

do {
  printf("i is %d\n", i);
  i++;
} while (i < 10);

printf("All done!\n");

上面例子中,变量i并不满足小于10的条件,但是循环体还是会执行一次。

6.for 语句

for语句是最常用的循环结构,通常用于精确控制循环次数。

objectivec 复制代码
for (initialization; continuation; action)
  statement;

上面代码中,for语句的条件部分(即圆括号里面的部分)有三个表达式。

  • initialization:初始化表达式,用于初始化循环变量,只执行一次。
  • continuation:判断表达式,只要为true,就会不断执行循环体。
  • action:循环变量处理表达式,每轮循环结束后执行,使得循环变量发生变化。

循环体部分的statement可以是一条语句,也可以是放在大括号里面的复合语句。下面是一个例子。

objectivec 复制代码
for (int i = 10; i > 0; i--)
  printf("i is %d\n", i);

上面示例中,循环变量ifor的第一个表达式里面声明,该变量只用于本次循环。离开循环体之后,就会失效。

条件部分的三个表达式,每一个都可以有多个语句,语句与语句之间使用逗号分隔。

objectivec 复制代码
int i, j;
for (i = 0, j = 999; i < 10; i++, j--) {
  printf("%d, %d\n", i, j);
}

上面示例中,初始化部分有两个语句,分别对变量ij进行赋值。

for的三个表达式都不是必需的,甚至可以全部省略,这会形成无限循环。

objectivec 复制代码
for (;;) {
  printf("本行会无限循环地打印。\n" );
}

上面示例由于没有判断条件,就会形成无限循环。

7.break 语句

break语句有两种用法。一种是与switch语句配套使用,用来中断某个分支的执行,这种用法前面已经介绍过了。另一种用法是在循环体内部跳出循环,不再进行后面的循环了。

objectivec 复制代码
for (int i = 0; i < 3; i++) {
  for (int j = 0; j < 3; j++) {
    printf("%d, %d\n", i, j);
    break;
  }
}

上面示例中,break语句使得循环跳到下一个i

objectivec 复制代码
while ((ch = getchar()) != EOF) {
  if (ch == '\n') break;
  putchar(ch);
}

上面示例中,一旦读到换行符(\n),break命令就跳出整个while循环,不再继续读取了。

注意,break命令只能跳出循环体和switch结构,不能跳出if结构。

objectivec 复制代码
if (n > 1) {
  if (n > 2) break; // 无效
  printf("hello\n");
}

上面示例中,break语句是无效的,因为它不能跳出外层的if结构。

8.continue 语句

continue语句用于在循环体内部终止本轮循环,进入下一轮循环。只要遇到continue语句,循环体内部后面的语句就不执行了,回到循环体的头部,开始执行下一轮循环。

objectivec 复制代码
for (int i = 0; i < 3; i++) {
  for (int j = 0; j < 3; j++) {
    printf("%d, %d\n", i, j);
    continue;
  }
}

上面示例中,有没有continue语句,效果一样,都表示跳到下一个j

objectivec 复制代码
while ((ch = getchar()) != '\n') {
  if (ch == '\t') continue;
  putchar(ch);
}

上面示例中,只要读到的字符是制表符(\t),就用continue语句跳过该字符,读取下一个字符。

9.goto 语句

goto 语句用于跳到指定的标签名。这会破坏结构化编程,建议不要轻易使用,这里为了语法的完整,介绍一下它的用法。

objectivec 复制代码
char ch;

top: ch = getchar();

if (ch == 'q')
  goto top;

上面示例中,top是一个标签名,可以放在正常语句的前面,相当于为这行语句做了一个标记。程序执行到goto语句,就会跳转到它指定的标签名。

objectivec 复制代码
infinite_loop:
  print("Hello, world!\n");
  goto infinite_loop;

上面的代码会产生无限循环。

goto 的一个主要用法是跳出多层循环。

objectivec 复制代码
for(...) {
  for (...) {
    while (...) {
      do {
        if (some_error_condition)
          goto bail;    
      } while(...);
    }
  }
}
    
bail:
// ... ...

上面代码有很复杂的嵌套循环,不使用 goto 的话,想要完全跳出所有循环,写起来很麻烦。

goto 的另一个用途是提早结束多重判断。

objectivec 复制代码
if (do_something() == ERR)
  goto error;
if (do_something2() == ERR)
  goto error;
if (do_something3() == ERR)
  goto error;
if (do_something4() == ERR)
  goto error;

上面示例有四个判断,只要有一个发现错误,就使用 goto 跳过后面的判断。

注意,goto 只能在同一个函数之中跳转,并不能跳转到其他函数。

相关推荐
悠哉悠哉愿意2 分钟前
【数学建模学习笔记】机器学习分类:KNN分类
学习·机器学习·数学建模
TDengine (老段)6 分钟前
TDengine 时间函数 TODAY() 用户手册
大数据·数据库·物联网·oracle·时序数据库·tdengine·涛思数据
四谎真好看9 分钟前
Java 学习笔记(进阶篇2)
java·笔记·学习
码界奇点15 分钟前
KingbaseES一体化架构与多层防护体系如何保障企业级数据库的持续稳定与弹性扩展
数据库·架构·可用性测试
程序猿炎义18 分钟前
【NVIDIA AIQ】自定义函数实践
人工智能·python·学习
小陈phd31 分钟前
高级RAG策略学习(四)——上下文窗口增强检索RAG
人工智能·学习·langchain
悟乙己38 分钟前
数据科学家如何更好地展示自己的能力
大数据·数据库·数据科学家
皆过客,揽星河1 小时前
mysql进阶语法(视图)
数据库·sql·mysql·mysql基础语法·mysql进阶语法·视图创建修改删除
黑客思维者1 小时前
《我是如何用C语言写工控系统的漏洞和Bug》连载(1)内容大纲
c语言·bug·工控漏洞
中国胖子风清扬1 小时前
Rust 序列化技术全解析:从基础到实战
开发语言·c++·spring boot·vscode·后端·中间件·rust