所谓控制流语句就是用来控制程序指令执行的次序,比如,如果条件满足执行语句A,否则,执行语句B。
在讲述具体的控制流语句之前,先了解一下语句和程序块是有必要的
x = 0;
x++;
printf("Hello");
在C语言中,分号是语句结束符。
if(a > 0) { // 程序块开始
int x, y;
x = 1;
y = x + 2;
} // 程序块结束,} 后面不需要加分号
if-else语句用于条件判定,表示如果…,否则…,其语法如下:
if(表达式)
语句1;
else
语句2;
其中,else部分是可选的。该程序执行时,先计算表达式的值,如果其值为真(即表达式的值非0),则执行语句1,如果其值为假(即表达式的值为0),则执行语句2。
看一个例子:
#include <stdio.h>
int main()
{
int n = 5;
char s[] = "hello";
if (n > 0)
for(int i =0; i<n;i++)
if(s[i] > 0)
printf("%c", s[i]);
else
printf("n为负数");
return 0;
}
如上程序,从缩进结构可以明确的表明设计意图,但编译器不一定能get到,它可能会将else与内层的if配对,这种错误是很难发现的,因此我们建议在有if语句嵌套的情况下使用花括号。例如:
#include <stdio.h>
int main()
{
int n = 5;
char s[] = "hello";
if (n > 0) {
for (int i = 0; i < n;i++) {
if (s[i] > 0)
printf("%c", s[i]);
}
}
else
printf("n为负数");
return 0;
}
else-if用于多路判定
if(表达式)
语句;
else if(表达式)
语句;
else if(表达式)
语句;
else if(表达式)
语句;
else
语句;
上述程序中的各表达式将被依次求值,一旦某个表达式的结果为真,执行与之对应的语句,并终止整个语句序列。例如:
#include <stdio.h>
int main()
{
int score = 70;
if (score >= 90) {
printf("优秀");
} else if (score >= 80) {
printf("良好");
} else if (score >= 60) {
printf("及格");
} else {
printf("不及格");
}
return 0;
}
switch语句用于多路判定,它测试表达式是否与给定的一些常量整数值中的某一个值匹配,并执行相应的分支动作。
switch(表达式)
case 常量表达式: 语句序列
case 常量表达式: 语句序列
default: 语句序列
#include <stdio.h>
// 编写一个程序,统计输入中各个数字(0-9)、空白符(空格,水平制表符,换行符)、其他字符出现的次数。
int main()
{
int ndigit[10]; // 存放各个数字出现的次数
int nwhite; // 空白符出现的次数
int nother; // 其他字符出现的次数
for (int i = 0; i < 10;i++)
ndigit[i] = 0;
nwhite = nother = 0;
char c; // 输入的字符
while ((c = getchar()) != EOF) {
switch (c) {
case '0': case '1':
case '2': case '3':
case '4': case '5':
case '6': case '7':
case '8': case '9':
ndigit[c - '0']++;
break;
case ' ':
case '\t':
case '\n':
nwhite++;
break;
default:
nother++;
break;
}
}
for (int i = 0; i < 10;i++) {
printf("%d出现的次数:%d\n", i, ndigit[i]);
}
printf("空白符出现的次数:%d\n", nwhite);
printf("其他字符出现的次数:%d\n", nother);
return 0;
}
while(表达式)
语句
for(表达式1;表达式2;表达式3)
语句
它等价于
表达式1
while(表达式2)
语句
表达式3
while和for这两种循环在循环体执行前对终止条件进行测试,与此相反,do-while循环在循环体执行之后测试终止条件,这样,循环体至少被执行一次。
do {
语句;
} while (表达式);
先执行循环体,再测试表达式,如果表达式为真,继续执行循环体,直到表达式结果为假,退出循环
在需要的时候提前退出循环,是很有用的操作。break语句可以用于从for、while、do-while循环中提前退出,就如同在switch中提前退出一样。
C语言提供了可随意滥用的goto语句以及标记跳转位置的标号。从理论上讲,goto语句是没有必要的,实践中不使用goto也可以很容易地写出代码。但是,在某些场合下goto还是用的着的。最常见的用法是终止程序在某些深度嵌套的结构中的处理过程。例如,一次跳出两层或多层循环。这种情况下使用break是不能达到目的的,它只能从最内层循环退出到上一级的循环。
下面是使用goto的一个例子:
#include <stdio.h>
int main()
{
int r = 0;
for (;;)
for (int i = 0; i < 10; i++)
if (i > 5) {
r = i;
goto error;
}
error:
printf("%d", r);
return 0;
}
再看一个例子,考虑判定两个数组a和b中是否有相同元素的问题。一种可能的解决办法是
#include <stdio.h>
int main()
{
int a[10];
int b[6];
for (int i = 0;i < 10; i++) {
a[i] = 1;
}
for (int i = 0;i < 6; i++) {
if (i = 5) {
b[i] = 1;
}
else {
b[i] = 2;
}
}
int ia = 0;
int ib = 0;
int res = 0;
for (int i = 0; i < 10; i++)
for (int j = 0; j < 6; j++)
if (a[i] == b[j]) {
ia = i;
ib = j;
res = a[i];
goto found;
}
found:
printf("%d\t%d\t%d", ia, ib, res);
return 0;
}
所有使用了goto的语句都可以改写成不带goto,但可能会增加一些额外的测试或变量,例如,上面的程序可以改写成:
#include <stdio.h>
int main()
{
int a[10];
int b[6];
for (int i = 0;i < 10; i++) {
a[i] = 1;
}
for (int i = 0;i < 6; i++) {
if (i = 5) {
b[i] = 1;
}
else {
b[i] = 2;
}
}
int ia = 0;
int ib = 0;
int res = 0;
int found = 0;
for (int i = 0; i < 10; i++)
{
if (found) {
break;
}
for (int j = 0; j < 6; j++)
if (a[i] == b[j]) {
ia = i;
ib = j;
res = a[i];
found = 1;
break;
}
}
if(found)
printf("%d\t%d\t%d", ia, ib, res);
return 0;
}
大多数情况下,使用goto的程序比没有使用goto的程序要难以理解和维护,少数情况除外,比如我们前面的几个例子。尽管问题并不太严重,但我们还是建议尽可能少的使用goto语句。