C语言入门系列:流程控制

一,C代码执行顺序

默认情况下,C语言程序从main()函数开始执行,随后按源代码中语句出现的顺序逐一执行。

这意味着,如果不考虑任何控制结构,程序会自上而下,逐行执行每条语句,直到遇到函数调用、返回语句或程序结束。

但是,在实际编程中,很多任务和逻辑无法仅通过简单的从上到下的顺序执行来完成。以下通过几个典型场景来说明这一点:

1. 条件执行:决定性操作

假设你正在编写一个程序来判断一个数是正数、负数还是零。

如果不使用控制语句,程序将无法根据输入的数值做出不同的反应,因为所有的操作都将按顺序执行,无法选择性地执行特定代码。

使用if语句,可以轻松实现这一点:

#include <stdio.h>

int main() {
    int num = 5;
    
    if (num > 0) {
        printf("正数\n");
    } else if (num < 0) {
        printf("负数\n");
    } else {
        printf("零\n");
    }
    
    return 0;
}

2. 循环处理:重复性任务

如果你需要打印出1到10的数字,仅仅依靠顺序执行是不够的,因为你需要让相同的打印操作重复执行10次。

对于这个星期,调用10次printf即可。但如果是重复1万次呢,在代码中调用1万次printf,那也太傻了吧?

这时,循环控制语句(如for循环)就显得尤为重要:

#include <stdio.h>

int main() {
    for(int i = 1; i <= 10; i++) {
        printf("%d ", i);
    }
    printf("\n");
    
    return 0;
}

3. 跳出循环:提前结束或跳过

在某些情况下,可能需要在满足特定条件时提前结束循环,或者在循环内部的某些点跳过某些步骤。这时,breakcontinue控制语句就发挥了作用:

#include <stdio.h>

int main() {
    for(int i = 1; i <= 10; i++) {
        if(i == 5) {
            printf("遇到5,提前结束循环\n");
            break; // 跳出循环
        }
        if(i % 2 == 0) {
            continue; // 跳过偶数,不打印
        }
        printf("%d ", i);
    }
    printf("\n");
    
    return 0;
}

二,控制类型

C语言中的流程控制语句可以大致分为以下几类:

  • 条件分支语句
  • 循环语句
  • 跳转语句
  • 其他控制

1. 条件分支语句

  • if 语句:基于一个条件,决定是否执行某段代码。
  • 三元运算符(条件运算符)?::一种简洁的条件表达式形式,用于赋值操作,根据条件选择两个表达式之一。
  • switch 语句:用于多路分支选择,根据不同的表达式值执行不同的代码块。

2. 循环语句

  • while 语句:只要给定条件为真,就重复执行一段代码。
  • do…while 结构:先执行循环体,然后检查条件是否为真,如果是,则继续执行循环。
  • for 语句:一种复合循环结构,集成了初始化、条件检查和迭代更新于一身。

3. 跳转语句

  • break 语句:用于提前退出循环或switch语句。
  • continue 语句:跳过当前循环迭代的剩余部分,直接开始下一次迭代。
  • goto 语句:允许程序跳转到同一函数内的指定标签处,虽然可用,但因其可能引起代码混乱和可读性差,现代编程实践中通常不鼓励使用。

4. 其他控制结构

  • 虽然不是C语言标准库直接提供的流程控制语句,但通过组合基本的流程控制语句,可以实现更复杂的控制结构,如:
    • 循环嵌套:一个循环内部包含另一个循环。
    • 条件循环:在循环条件中使用逻辑表达式来控制循环的执行。
    • 提前返回(return):在函数中使用,可以立即结束函数的执行并返回一个值(对于非void类型函数)。

三,条件分支语句

条件分支语句让程序能够根据条件跳过某些代码、执行特定代码

1. if 语句

基本语法

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

if (expression) statement

上面式子中,表达式expression为真(值不为0)时,就执行statement语句,statment部分称之为代码块

if后面的判断条件expression外面必须有圆括号,否则会报错。代码块可以是一条语句或多条语句,多条语句必须包含在一对大括号内。

下面是一个一条语句例子。

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 (x == 10) {
  printf("x is 10\n");
}

if-else

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");
}

在这里插入图片描述

强烈建议,if和else后的代码块不要省略大括号,哪怕在只有一行语句的情况下。

2. 三元运算符 ?:

三元运算符是if...else的简写形式,用于简单的条件赋值。其语法结构如下。

<expression1> ? <expression2> : <expression3>

下面是一个示例。

#include <stdio.h>

int main() {
    int score = 75;
    char result = (score >= 60) ? 'P' : 'F';
    printf("Your grade is: %c\n", result);
    return 0;
}

这段代码可以用if-else改写。

#include <stdio.h>

int main() {
    int score = 75;
    char result;
    if (score >= 60) {
		result = 'P';
    } else {
		result = 'F';
	}
    printf("Your grade is: %c\n", result);
    return 0;
}

3. switch 语句

switch语句根据不同的情况执行不同代码块,每个情况由一个或多个case标签指定。

switch 语句可以理解为一种特殊形式的 if-else 结构,switch 语句更易用、可读性更好。

switch (expression) {
  case value1: statement1
  case value2: statement2
  default: statement3
}

这个结构表达的是,expression 的值匹配到某个case后,执行对应的statement。

举例如下。

#include <stdio.h>

int main() {
    int day = 3;
    
    switch(day) {
        case 1:
            printf("Monday\n");
            break;
        case 2:
            printf("Tuesday\n");
            break;
        case 3:
            printf("Wednesday\n");
            break;
        default:
            printf("Invalid day\n");
    }
    
    return 0;
}

上面switch语句表达的是,根据整数类型变量day的值选择执行特定的代码。若day的值是1,输出Monday,如果是2,输出Tuesday,如果是3,输出Wednesday,如果都不是,执行default对应的语句,输出Invalid day。因为上述代码中变量day的值是3,所以会执行printf("Wednesday\n");,输出Wednesday

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

上述代码在执行代码printf("Wednesday\n");后,遇到break语句,跳出switch语句,执行其后的语句return 0;

如下代码,第2个case的代码块没有break语句。

#include <stdio.h>

int main() {
    int day = 2;
    
    switch(day) {
        case 1:
            printf("Monday\n");
            break;
        case 2:
            printf("Tuesday\n");
        case 3:
            printf("Wednesday\n");
            break;
        default:
            printf("Invalid day\n");
    }
    
    return 0;
}

因为day的值是2,所以执行 printf("Tuesday\n");,但由于没有break语句,会接着执行第三个case的代码块,即执行代码printf("Wednesday\n");,然后因为break语句,跳出switch语句。

本意是当day值为3时,才输出Wednesday,但因为第2个case后的代码块缺少break,导致错误发生。

在这里插入图片描述
如果要省略case后代码块的break,一定要明确不会出现意外的情况。

四,循环语句

1. while 语句

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

while (expression)
  statement

statement部分称之为循环体

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

下面代码的作用是判断一个整数有多少位,用while循环实现。

#include <stdio.h>

int main() {
    int count = 0;
    int num = 2323233232;
    int tmpNum = num;
    while(tmpNum > 0) {
        count++;
        tmpNum= tmpNum / 10;
    }
    printf("num=%d是%d位数", num, count);
    return 0;
}

上述代码不够健壮,没有考虑临界情况,即当num = 0时,程序不能得出正确结果。

在使用循环体时,要特别注意临界问题。

我们做如下优化:

#include <stdio.h>

int main() {
    int count = 0;
    int num = 2323233232;
    int tmpNum = num;
    // 临界情况,特殊处理
    if (num == 0) {
		count++;
    }
    while(tmpNum > 0) {
        count++;
        tmpNum= tmpNum / 10;
    }
    printf("num=%d是%d位数", num, count);
    return 0;
}

注意,当循环体中只有一条语句时,可以省略大括号。有多条语句时,不能省略。但强烈建议,即便只有一条语句,也不要省略大括号。

#include <stdio.h>

int
main ()
{
  int day = 2;

  // 省略大括号,语法正确
  while (day < 3)
	printf ("day=%d\n", day++);
	
  printf ("day=%d", day++);

  return 0;
}

加上大括号,可读性更强。

#include <stdio.h>

int
main ()
{
  int day = 2;

  // 省略大括号,语法正确
  while (day < 3) {
	printf ("day=%d\n", day++);
  }
	
  printf ("day=%d", day++);

  return 0;
}

2. do…while 结构

while类似,最大的区别是do-while先执行一次循环体,然后检查条件,所以其至少会执行一次循环体。

用do-while重写计算整数位数的例子。

#include <stdio.h>

int main() {
    int count = 0;
    int num = 2323233232;
    int tmpNum = num;
   
    do {
        count++;
        tmpNum= tmpNum / 10;
    } while(tmpNum > 0)
    
    printf("num=%d是%d位数", num, count);
    return 0;
}

如果用do-while,临界情况num = 0就无需特殊处理。

同样,我们建议循环体始终包裹在大括号中。

3. for 语句

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

for (initialization; continuation; action)
  statement;

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

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

int main() {
    for(int i = 0; i < 5; i++) {
        printf("%d ", i);
    }
    printf("\n");
    
    return 0;
}

五,跳转语句

1. break 语句

break用于立即退出最内层循环或switch语句。

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。

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

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

上面示例中,break语句是无效的,因为它不能跳出外层的if结构,还会继续执行printf("hello\n")

注意事项

  • 在多层循环中,break只跳出当前层循环。

2. continue 语句

continue使程序跳过当前循环体剩余部分,直接开始下一次循环迭代。

#include <stdio.h>

int main() {
    for(int i = 0; i < 10; i++) {
        if(i % 2 == 0) { // Skip even numbers
            continue;
        }
        printf("%d ", i);
    }
    printf("\n");
    
    return 0;
}

上面示例中,只要是偶数,就用continue语句跳过该数字,执行下一次循环

3. goto 语句

goto允许无条件跳转到标记的语句,但在现代编程中不鼓励使用,因为它可能导致代码结构混乱,不易理解,所以这里一笔带过。

#include <stdio.h>

int main() {
    int i = 0;
start:
    printf("%d ", i);
    i++;
    if(i < 5) goto start; // 不推荐使用
    printf("\n");
    
    return 0;
}

尽量避免使用goto,考虑使用循环或函数替代以提高代码质量。

六,其他控制结构

虽然不是C语言标准库直接提供的流程控制语句,但通过组合基本的流程控制语句,可以实现更复杂的控制结构,如:

  • 循环嵌套:一个循环内部包含另一个循环。
  • 条件循环:在循环条件中使用逻辑表达式来控制循环的执行。
  • 提前返回(return):在函数中使用,可以立即结束函数的执行并返回一个值(对于非void类型函数)。
  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小手追梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值