7.流程控制

简介: 7.流程控制

七、流程控制

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

1.if 语句

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

if (expression) statement

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

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

if (x == 10) printf("x is 10");

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

if (x == 10)
  printf("x is 10\n");

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

if (line_num == MAX_LINES) {
  line_num = 0;
  page_num++;
}

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

if (expression) statement
else statement

下面是一个例子。

if (i > j)
  max = i;
else
  max = j;


如果 else 的语句部分多于一行,同样可以把它们放在大括号里面。else 可以与另一个 if 语句连用,构成多重判断。

if (expression)
  statement
else if (expression)
  statement
...
else if (expression)
  statement
else
  statement

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

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 。

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 的简写形式。

<expression1> ? <expression2> : <expression3>

这个操作符的含义是,表达式 expression1 如果为 true (非0值),就执行 expression2 ,否则执行expression3 。下面是一个例子,返回两个值之中的较大值。

(i > j) ? i : j;

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

if (i > j)
  return i;
else
  return j;

3.switch 语句

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

switch (expression) {
  case value1: statement
  case value2: statement
  default: statement
}

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

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 ,就会导致继续执行下一个 case 或 default 分支。

switch (grade) {
  case 0:
    printf("False");
  case 1:
    printf("True");
    break;
  default:
    printf("Illegal");
}

上面示例中, case 0 的部分没有 break 语句,导致这个分支执行完以后,不会跳出 switch 结构,继续执行 case 1 分支。利用这个特点,如果多个 case 分支对应同样的语句体,可以写成下面这样。

switch (grade) {
  case 0:
  case 1:
    printf("True");
    break;
  default:
    printf("Illegal");
}

上面示例中, case 0 分支没有任何语句,导致 case 0 和 case 1 都会执行同样的语句体。case 后面的语句体,不用放在大括号里面,这也是为什么需要 break 的原因。default 分支用来处理前面的 case 都不匹配的情况,最好放在所有 case 的后面,这样就不用写 break语句。这个分支是可选的,如果没有该分支,遇到所有的 case 都不匹配的情况,就会直接跳出整个switch 代码块。

4.while 语句

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

while (expression)
  statement

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

while (i < n)
  i = i + 2;

上面示例中,只要 i 小于 n , i 就会不断增加2。如果循环体有多个语句,就需要使用大括号将这些语句组合在一起。

while (expression) {
  statement;
  statement;
}

下面是一个例子。

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

上面代码中,循环体会执行10次,每次将 i 增加 1 ,直到等于 10 才退出循环。只要条件为真, while 会产生无限循环。下面是一种常见的无限循环的写法。

while (1) {
  // ...
}

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

5.do…while 结构

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

do statement
while (expression);

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

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

上面示例中,变量 i 先减去1,再判断是否大于0。如果大于0,就继续减去1,直到 i 等于 0 为止。如果循环部分有多条语句,就需要放在大括号里面。

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

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

6.for 语句

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

for (initialization; continuation; action)
  statement;

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


initialization :初始化表达式,用于初始化循环变量,只执行一次。

continuation :判断表达式,只要为 true ,就会不断执行循环体。

action :循环变量处理表达式,每轮循环结束后执行,使得循环变量发生变化。

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

for (int i = 10; i > 0; i--)
  printf("i is %d\n", i);

上面示例中,循环变量 i 在 for 的第一个表达式里面声明,该变量只用于本次循环。离开循环体之后,就会失效。条件部分的三个表达式,每一个都可以有多个语句,语句与语句之间使用逗号分隔。

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

上面示例中,初始化部分有两个语句,分别对变量 i 和 j 进行赋值。for 的三个表达式都不是必需的,甚至可以全部省略,这会形成无限循环。

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

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

7.break 语句

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

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

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

while ((ch = getchar()) != EOF) {
  if (ch == '\n') break;
  putchar(ch);
}

上面示例中,一旦读到换行符( \n ), break 命令就跳出整个 while 循环,不再继续读取了。注意, break 命令只能跳出循环体和 switch 结构,不能跳出 if 结构。

if (n > 1) {
  if (n > 2) break; // 无效
  printf("hello\n");
}

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

8.continue 语句

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

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

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

while ((ch = getchar()) != '\n') {
  if (ch == '\t') continue;
  putchar(ch);
}

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

9.goto 语句

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

char ch;
top: ch = getchar();
if (ch == 'q')
  goto top;

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

infinite_loop:
  print("Hello, world!\n");
  goto infinite_loop;

上面的代码会产生无限循环。goto 的一个主要用法是跳出多层循环。

for(...) {
  for (...) {
    while (...) {
      do {
        if (some_error_condition)
          goto bail;    
     } while(...);
   }
 }
}
bail:
// ... ...

上面代码有很复杂的嵌套循环,不使用 goto 的话,想要完全跳出所有循环,写起来很麻烦。goto 的另一个用途是提早结束多重判断。

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 只能在同一个函数之中跳转,并不能跳转到其他函数。


目录
相关文章
|
存储 关系型数据库 MySQL
2024年Java秋招面试必看的 | MySQL调优面试题
随着系统用户量的不断增加,MySQL 索引的重要性不言而喻,对于后端工程师,只有在了解索引及其优化的规则,并应用于实际工作中后,才能不断的提升系统性能,开发出高性能、高并发和高可用的系统。 今天小编首先会跟大家分享一下MySQL 索引中的各种概念,然后介绍优化索引的若干条规则,最后利用这些规则,针对面试中常考的知识点,做详细的实例分析。
613 0
2024年Java秋招面试必看的 | MySQL调优面试题
搭建一个简单的直播网站
我是一个比较爱看直播的人,经常空闲的时候会看一看LOL、吃鸡的直播。正好最近在研究阿里云的视频直播服务,突发奇想,自己来搭建一个简单的直播平台!主要会用到的东西有:视频直播、ECS、OBS、阿里播放器。
11278 1
|
缓存 API 定位技术
.tpk格式文件简介
1、.tpk格式的文件是什么?       tpk是ArcGIS10.1推出的一种新的数据文件类型,主要是用于将切片文件打包形成离线地图包,tpk可以在ArcGIS Runtime或者ArcGIS for Android/iOS中作为切片底图被加载。
4480 0
|
5月前
|
传感器 算法 机器人
医疗引导机器人技术架构解析:决定品牌竞争力的核心要素
智慧医院建设推动医疗引导机器人迈向智能化,其核心技术涵盖多传感器融合导航、垂直领域大模型与RAG语义理解、主动视觉交互、跨楼层梯控及HIS系统深度集成。本文从技术架构出发,剖析环境感知、认知决策与系统协同的关键突破,揭示机器人如何成为连接物理空间与数字医疗的核心终端。
|
8月前
|
安全 云计算
面向对象
面向对象三大特性——封装、继承、多态,是构建软件世界的哲学基石。封装隐藏细节,提升安全与模块化;继承实现代码复用,构建层次体系;多态增强灵活性,支持统一接口下的多样化行为。三者协同,形成高内聚、低耦合、易扩展的系统设计,不仅是编程技术,更是应对复杂性的思维智慧。(238字)
|
10月前
|
缓存 监控 API
1688平台开放接口实战:如何通过API获取店铺所有商品数据(Python示列)
本文介绍如何通过1688开放平台API接口获取店铺所有商品,涵盖准备工作、接口调用及Python代码实现,适用于商品同步与数据监控场景。
|
存储
半自动:图床解决方案,使用115当图床使用 获取图片直链
半自动:图床解决方案,使用115当图床使用 获取图片直链
848 5
|
机器学习/深度学习 DataWorks 安全
CDP是什么?
CDP是什么?
1237 0
|
存储 关系型数据库 Java
极速体验DolphinScheduler 3.2.1 Standalone 版[一]
极速体验DolphinScheduler 3.2.1 Standalone 版[一]
338 0
|
XML JSON Java
经验大分享:SpringCloud之Feign
经验大分享:SpringCloud之Feign
424 0