C语言控制语句详解:类型、示例与最佳实践

本文全面介绍C语言中的控制语句,包括决策语句(if-else、switch-case)、迭代语句(for、while、do-while)和跳转语句(break、continue、goto),通过实际代码示例展示其用法和最佳实践,帮助开发者掌握程序流程控制的核心技术。

C语言控制语句:类型、示例与用法

C语言中的控制语句(也称为控制结构)允许开发者管理程序的执行流程。这些控制指令包括条件控制语句,简化了决策、循环和分支,使得有条件或重复执行指令成为可能。

关键要点

  • C语言中的控制语句决定程序的执行流程,支持基于条件的决策、循环和分支。
  • C语言主要有三种控制语句类型:决策语句(if、else if、switch-case)、迭代语句(for、while、do-while)和跳转语句(break、continue、goto)。这些构成了C编程中控制结构的基础,使开发者能高效处理各种逻辑场景。
  • if-else语句根据真假条件执行代码块,语法强调使用括号表示条件,花括号表示代码块。
  • switch-case语句使用表达式的整数值提供结构化的多路分支方法。每个case以break结束以防止穿透。
  • 迭代语句如forwhiledo-while循环基于条件表达式重复执行代码块,每种循环类型提供不同的控制机制。
  • 嵌套控制结构,包括循环内的嵌套if-else和switch-case,允许在不同编程场景中进行复杂决策和重复任务。

什么是C语言中的控制语句

C语言中的控制语句是基于特定条件或重复管理程序执行流程的指令。它们允许开发者做出决策、重复任务或跳转到代码的特定部分。

控制语句的类型

C语言中有三种控制语句:

  1. 决策语句(if、if-else、switch-case)
  2. 迭代语句(for、while、do-while)
  3. 跳转语句(break、continue、goto)

决策语句

1. if-else语句

if-else语句是C语言控制流语句的重要组成部分,根据真假条件执行代码块。复杂决策通常涉及多个if-else语句或else-if语句,确保不同条件产生不同结果。

语法

1
2
3
4
5
if (condition) {
    // 条件为真时执行的语句
} else {
    // 条件为假时执行的语句
}
  • 如果条件为真,执行if块,程序继续执行其后的语句。
  • 如果条件为假且没有else块,程序跳过if块,移动到下一个语句。
  • else块仅在条件为假时需要运行特定代码时使用。

示例1:检查正负数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include<stdio.h>
int main() {
  int a;
  printf("\n Enter a number:");
  scanf("%d", &a);

  if(a>0) { 
    printf("\n The number %d is positive.",a);
  } else {
    printf("\n The number %d is negative.",a);
  }
  return 0;
}

示例2:比较两个字符串

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <string.h>

int main() {
    char a[20], b[20];

    printf("\n Enter the first string:");
    scanf("%s",a);
    printf("\n Enter the second string:");
    scanf("%s",b);

    if((strcmp(a,b)==0)) {
        printf("\nStrings are the same");
    } else {
        printf("\nStrings are different");
    }

    return 0;
}

上述程序比较两个字符串是否相同。使用strcmp函数实现,该函数在string.h文件中声明:

1
int strcmp(const char *s1, const char *s2);

它比较s1指向的字符串和s2指向的字符串,并返回:

  • 0 如果字符串相等
  • 负数 如果第一个字符串小于第二个
  • 正数 如果第一个字符串大于第二个

注意:比较区分大小写。对于不区分大小写的比较,使用strcasecmp()(非标准)。

嵌套if和if-else语句

也可以将一个if-else语句嵌入或嵌套在另一个内部。当需要评估多个条件时,嵌套很有用。

嵌套if-else语句的一般格式:

1
2
3
4
5
6
7
8
9
if(condition1) {
    // condition1为真时的语句
} else if(condition2) {
    // condition2为真时的语句
} else if(conditionN) {
    // conditionN为真时的语句
} else {
    // 所有条件都不为真时的语句
}

这种结构也称为if-else阶梯。在执行嵌套if-else语句时,执行在第一个评估为真的条件处停止,并跳过剩余块。

如果所有条件都不为真,则执行最后一个else块,或者如果没有else块,控制转移到else-if阶梯之后的下一条指令。

示例:找出三个数中的最大值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include<stdio.h>
int main() {
    int a = 6, b = 5, c = 10;

    if(a > b) {
        if(a > c) {
            printf("\nGreatest is: %d", a);
        } else {
            printf("\nGreatest is: %d", c);
        }
    } else if(b > c) {
        printf("\nGreatest is: %d", b);
    } else {
        printf("\nGreatest is: %d", c);
    }
    return 0;
}

上述程序比较三个整数量并打印最大值。第一个if语句比较a和b的值:

  • 如果a>b为真,进入嵌套if比较a和c
  • 如果a > c,打印a。否则打印c
  • 如果第一个条件失败(a > b为假),检查b > c。如果为真,打印b,否则打印c

最佳实践和常见错误:

  • 单语句使用花括号:即使if或else后只有一个语句,也要用花括号{}括起来
  • 避免赋值代替比较:使用==进行比较,而不是=(赋值)
  • 缩进很重要:保持一致的缩进以提高可读性并避免错误
  • 测试边界情况:验证输入和输出,特别是在嵌套if-else结构中,以处理边界条件

2. Switch语句

switch-case语句用于多路分支,其中变量或表达式的值与预定义case匹配。在测试相等性时,它是替代长链if-else的理想选择。

但是,使用switch语句时必须小心,因为缺少break语句会导致穿透行为,执行后续case并导致意外结果。

语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
switch (expression) {
  case value1:
    // 代码段1
    break;
  case value2:
    // 代码段2;
    break;
  ...
  case valueN:
    // 代码段N
    break;
  default:
    // 默认代码段
}

此表达式的值在程序执行期间生成或作为用户输入读取。选择值与表达式值相同的case并执行。可选的default标签用于指定当表达式的值与任何case值都不匹配时要执行的代码段。

如果在第三个case末尾没有break语句,switch语句会过早执行所有后续case,导致意外结果。

如果存在break,只选择并执行所需的case,之后控制转移到switch语句之后的下一条语句。

default后没有break,因为在default case之后,控制无论如何都会转移到switch之后的下一条语句。

示例1:打印星期几

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<stdio.h>

int main() {
  int day;
  printf("\nEnter the number of the day:");
  scanf("%d",&day);

  switch(day) {
      case 1:
        printf("Sunday");
        break;
      case 2:
        printf("Monday");
        break;
      case 3:
        printf("Tuesday");
        break;
      case 4:
        printf("Wednesday");
        break;
      case 5:
        printf("Thursday");
        break;
      case 6:
        printf("Friday");
        break;
      case 7:
        printf("Saturday");
        break;
      default:
        printf("Invalid choice");
  }
  return 0;
}

这个基本程序演示了switch-case结构的使用。根据用户输入执行相应的case,break语句防止执行后续case。例如,如果输入是5,输出将是Thursday。

所有使用C语言控制结构(如switch-case语句)编写的程序也可以使用if-else语句实现。

然而,C语言中的控制流语句(如switch-case)在多路分支中提供更好的可读性和性能。

switch-case语句特别适用于基于菜单的应用程序或处理特定用户输入。与嵌套if-else语句相比,它们更高效且更易读,特别是在从固定选择集中选择时。

示例2:文件处理的菜单驱动程序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<stdio.h>

int main() {
  int choice;
  printf("\nPlease select from the following options:");
  printf("\n1. Add a record at the end of the file.");
  printf("\n2. Add a record at the beginning of the file.");
  printf("\n3. Add a record after a particular record.");
  printf("\nPlease enter your choice (1/2/3): ");
  scanf("%d", &choice);

  switch(choice) {
      case 1:
        // 在文件末尾添加记录的代码
        break;
      case 2:
        // 在文件开头添加记录的代码
        break;
      case 3:
        // 在特定记录后添加记录的代码
        break;
      default:
        printf("\nWrong Choice");
  }
  return 0;
}

上述switch-case示例通常涉及将switch-case结构嵌套在迭代结构(如do-while)中。

最佳实践和常见错误:

  • 始终使用Break:除非有意穿透,否则在每个case后包含break
  • 默认case放置:将default放在末尾以提高可读性
  • 测试所有输入值:确保输入匹配有效case值,并使用default case正确处理无效输入
  • 避免复杂表达式:对case使用简单常量,因为不支持变量或范围
  • 缩进和格式化:遵循一致的缩进以保持清晰

迭代语句

迭代语句用于重复执行特定指令集,直到满足特定条件或固定次数的迭代。

1. for循环

for循环是一个预测试循环,在循环执行前评估条件。它最适用于事先知道迭代次数的情况。

语法

1
2
3
for(initialization; termination; increment/decrement) { 
    //要执行的语句 
}

for循环由三个表达式组成:

  • 初始化表达式:初始化循环索引。循环索引控制循环动作。初始化表达式仅在循环开始时执行一次。
  • 终止表达式:表示循环继续执行必须为真的条件。
  • 递增/递减表达式:每次迭代后执行以更新循环索引的值。

示例:斐波那契数列

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include<stdio.h>
int main() {
  int i, n, a = 0, b = 1, sum;
  printf("Enter the number of terms: ");
  scanf("%d", &n);

  printf("%d %d", a, b);

  for(i = 2; i < n; i++) {
    sum = a + b;
    printf(" %d", sum);
    a = b;
    b = sum;
  }

  return 0; 
}

上述程序使用for循环打印数列:0,1,1,2,3,5,8,13…到n项。

  • 初始化:设置i = 2,因为前两项(0和1)已打印
  • 条件:继续执行直到i < n
  • 递增:每次迭代后i增加1

如果输入数字是7,输出将是:

1
0 1 1 2 3 5 8

for循环的变体

  1. 省略初始化表达式 在这种情况下,循环索引在for循环之前初始化。因此,for循环采用以下形式:
1
2
3
4
int i = 0; // 循环前初始化
for(; i < 5; i++) {
    printf("%d ", i);
}

当循环变量在循环外初始化时,此方法很有用。

注意:终止初始化表达式的分号位于条件表达式之前。

  1. 省略条件 在这种情况下,条件在for循环体内指定,通常使用if语句。while或do-while语句也可用于指定条件。因此for循环采用以下形式:
1
2
3
4
for(int i = 0; ; i++) {
    if(i == 5) break; // 在循环内指定条件
    printf("%d ", i);
}

这对于在循环体内处理条件退出的情况很有用。此外,终止条件的分号存在于for语句中。以下程序解释了如何省略条件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h> 
int main() {
  int i,n, a, b, sum=0;
  printf("Enter the number of terms:");
  scanf("%d",&n); 
  a=0;
  b=1;
  printf("%d\n %d", a, b);

  for(i=2; ;i++) {
    if(i==(n-1)) { //使用if语句指定条件
      break;
    }
    
    sum=a+b;
    printf("\n%d",sum);
    a=b;
    b=sum;
  }

  return 0;
}
  1. 省略递增/递减表达式: 在这种情况下,递增/递减表达式写在for循环体内。当只需要基于特定条件增加循环计数时,这很有用。
1
2
3
4
for(int i = 0; i < 5;) {
    printf("%d ", i);
    i++; // 循环体内递增
}
  1. 省略所有三个表达式: 也可以省略所有三个表达式,但它们应该以上述方式存在。如果所有三个表达式完全省略——即它们没有以上述方式提及——那么for循环变成无限或永不结束的循环。

在这种情况下,for循环采用以下形式:

1
2
3
for(;;) {
  //语句 
}

最佳实践和常见错误:

  • 始终更新循环变量:确保递增或递减防止无限循环
  • 使用花括号{}提高清晰度:即使循环内只有一个语句
  • 避免差一错误:仔细检查终止条件,特别是使用<或<=时
  • 使用边界值测试:用最小和最大值验证行为

2. while循环

while语句在特定条件为真时重复执行语句块。

1
2
3
while (condition) {
  //要执行的语句 
}

语句重复执行直到条件为真。

示例1:数字之和

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include<stdio.h>
int main() {
  int n, a, sum = 0;
  printf("\nEnter a number: ");
  scanf("%d", &n);

  while(n > 0) {
    a = n % 10; // 提取最后一位数字
    sum = sum + a; // 加到总和中
    n = n / 10; // 移除最后一位数字
  }

  printf("\nSum of the digits = %d", sum);
  return 0; 
}

上述程序使用while循环计算数字的各位数之和。例如,如果数字是456,while循环将在四次迭代中计算总和如下。 注意:%给出余数,/给出商。

  • 迭代1:n>0 条件为真(n=456) a=n%10=6; sum=sum+a=6; n=n/10=45; n的新值为45
  • 迭代2:n>0 条件为真(n=45) a=n%10=5; sum=sum+a=6+5=11; n=n/10=4; n的新值为4
  • 迭代3:n>0 条件为真(n=4) a=n%10=4; sum=sum+a=11+4=15; n=n/10=0; n的新值为0
  • 迭代4:n>0 条件为假(n=0)。第四次迭代后控制退出while循环并打印总和为15

示例2:回文检查

回文是一个数字,当其数字从右向左或从左向右读取时保持不变,例如343是回文,但342不是。

以下程序的逻辑是,如果数字的反转与原始数字相同,则输入的数字是回文,否则不是。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
int main() {
  int n, m, a, reverse = 0;
  printf("\nEnter a number: ");
  scanf("%d", &n);
  m = n;

  while(n > 0) {
    a = n % 10; // 提取最后一位数字
    reverse = reverse * 10 + a; // 构建反转数字
    n = n / 10; // 移除最后一位数字
  }

  if (m == reverse) {
    printf("\nThe number is a palindrome.");
  } else {
    printf("\nThe number is not a palindrome.");
  }
  return 0;
}

上述程序使用与数字之和程序几乎相同的逻辑。如该程序所示,n在最后一次迭代中变为0。然而,我们需要将n的原始值与数字的反转进行比较以确定是否是回文。

因此,在进入while循环之前,n的值存储在m中。后来将m与反转数比较以决定输入的数字是否是回文。

while循环的工作方式如下: 设n=343;

  • 迭代1:a=n%10=3; reverse=reverse10+a=010+3=3; n=n/10=34;
  • 迭代2:a=n%10=4; reverse=reverse10+a=310+4=34; n=n/10=3;
  • 迭代3:a=n%10=3; reverse=reverse10+a=3410+3=343; n=n/10=0;
  • 迭代4:n>0 条件假(n=0)。控制从while循环退出。

最佳实践和常见错误:

  • 无限循环:确保条件在循环内变化以避免无限执行
  • 初始化:在进入循环前正确初始化变量
  • 中断条件:需要提前退出时使用显式break语句
  • 边界情况:测试像0或负值这样的输入以处理所有场景

3. do-while循环

do-while循环是一个退出控制循环,意味着循环体在检查条件之前至少执行一次。

语法

1
2
3
4
do { 
  //要执行的语句;  
} 
while(condition);

while和do-while之间的区别在于,while循环是入口控制的——它在循环开始时测试条件,如果条件为假,甚至不会执行一次,而do-while循环是退出控制的——它在完成第一次迭代后在循环结束时测试条件。

对于许多应用程序,在循环开始时而不是结束时测试循环的延续更自然。因此,do-while语句比while语句使用频率低。

**示例1:数字之和

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计