7.C 控制语句:分支和跳转
一、if 语句
-
if 语句被称为分支语句或选择语句。因为它相当于一个交叉点,程序要在两条分支中选择一条执行。
-
if语句的通用形式如下:
if ( expression )
statement
如果对expression求值为真(非0),则执行statement;否则,跳过statement。与 while 循环一样,statement 可以是一条简单的语句也可以是复合语句
-
if 语句的结构和while 语句很相似,它们的主要区别是:如果满足条件可执行的话,if语句只能测试和执行一次,而while语句可以测试和执行多次。
二、if else 语句
-
简单形式的if语句可以让程序选择执行一条语句,或者跳过这条语句。C还提供了if else形式,可以在两条语句之间作选择。
-
if else语句的通用形式是:
if ( expression )
statement1
else
statement2
如果 expression 为真(非0),则执行 statement1;如果 expression 为假或0,则执行 else 后面的statement2。statement1 和 statement2 可以是一条简单语句或复合语句。
-
如果要在 if 和 else 之间执行多条语句,必须用花括号把这些语句括起来为一个块。
-
if 语句用于选择是否执行一个行为,而 if else 语句用于在两个行为之间选择。
2.1 另一个示例:介绍getchar( ) 和 putchar( )
-
getchar( ) 和 putchar( ):输入/输出函数。
-
getchar( ) 函数不带任何参数,它从输入队列中返回下一个字符。例如,下面的语句读取下一个字符输入,并把该字符的值赋给变量ch:
ch = getchar( ); 与 scanf("%c", &ch); 效果相同
-
putchar()函数打印它的参数。例如,下面的语句把之前赋给ch的值作为字符打印出来:
putchar(ch); 与 printf("%c", ch); 效果相同。
-
由于这些函数只处理字符,所以它们比更通用的scanf()和printf()函数更快、更简洁。
-
getchar( ) 和 putchar( ) 不需要转换说明,因为它们只处理字符。这两个函数通常定义在 stdio.h 头文件中(而且,它们通常是预处理宏,而不是真正的函数)。
2.2 多重选择else if
-
在程序中也可以用 else if 扩展 if else 结构模拟这种情况。
-
可以把多个else if语句连成一串使用,如下所示:
if (score < 1000) // else if 语句的通用形式(缩进后)
bonus = 0; // if (expression1)
else // statement1
if (score < 1500) // else if (expression2)
bonus = 1; // satement2
else // else if (expression3)
if (score < 2500) // statement3
bonus = 2; // else
else // statement4
bonus = 6;
/*该程序由一个if else语句组成,else部分包含另一个if else语句,
该if else语句的else部分又包含另一个if else语句。
第2个if else语句嵌套 在第1个if else语句中,第3个if else语句嵌套在第2个if else语句中。
2.3 else 与 if 配对
- 当有多个 if 时,如果没有花括号,else 与离它最近的 if 匹配,除非最近的 if 被花括号括起来。

三、逻辑运算符
-
逻辑运算符的运算对象通常是关系表达式。
-
! 运算符只需要一个运算对象,其他两个逻辑运算符都需要两个运算对象,左侧一个,右侧一个。
-
逻辑运算符的优先级比关系运算符低,所以不必在子表达式两侧加圆括号。
-
逻辑运算符:
![]()
-
假设exp1和exp2是两个简单的关系表达式,那么:
- 当且仅当exp1和exp2都为真时,exp1 && exp2才为真(都为真才真);
- 如果exp1或exp2为真,则exp1 || exp2为真(存在真即真);
- 如果exp1为假,则!exp1为真;如果exp1为真,则!exp1为假(相反)。
3.1 备选拼写:iso646.h头文件
- C99标准新增了可代替逻辑运算符 的拼写,它们被定义在ios646.h头文件中。
- 如果在程序中包含该头文件,便可用 and 代替 &&、or 代替||、not 代替 ! 。
3.2 优先级
- ! 运算符的优先级很高,比乘法运算符还高,与递增运算符的优先级相同,只比圆括号的优先级低。
- && 运算符的优先级比||运算符高,但是两者的优先级都比关系运算符低,比赋值运算符高。
- 举例:表达式a >b && b > c || b > d 相当于 ((a > b) && (b > c)) || (b > d)
3.3 求值顺序
-
除了两个运算符共享一个运算对象的情况外,C 通常不保证先对复杂表达式中哪部分求值。C 把先计算哪部分的决定权留给编译器的设计者,以便针对特定系统优化设计。
例如,apples = (5 + 3) * (9 + 6),可能先对表达式5 + 3求值,也可能先对表达式9 + 6求值。
-
但是,对于逻辑运算符是个例外,C保证逻辑表达式的求值顺序是从左往右。
-
&&和||运算符都是序列点,所以程序在从一个运算对象执行到下 一个运算对象之前,所有的副作用都会生效。
-
而且,C 保证一旦发现某个元素让整个表达式无效,便立即停止求值。
-
如,while ((c = getchar()) != ' ' && c != '\n') 440
如上代码所示,读取字符直至遇到第1 个空格或换行符。第1 个子表达式把读取的值赋给c,后面的子表达式会用到c 的值。如果没有求值循序的保证,编译器可能在给c赋值之前先对后面的表达式求值。
3.4 范围
-
&& 运算符可用于测试范围。
如,if (range >= 90 && range <= 100)
不能模仿数学写法写成,if (90 <= range <= 100),这样写的问题是代码有语义错误,而不是语法错误,所以编译器不会捕获这样的问题,且编译器会把测试表达式解释为:(90 <= range) <= 100
-
许多代码都用范围测试来确定一个字符是否是小写字母。该方法仅对于像ASCII这样的字符编码有效,这些编码中相邻字母与相 邻数字一一对应。
四、一个统计单词的程序
-
现在,我们可以编写一个统计单词数量的程序(即,该程序读取并报告单词的数量)。该程序还可以计算字符数和行数。
-
据此我们编写的伪代码如下:
读取一个字符
当有更多输入时
递增字符计数
如果读完一行,递增行数计数
如果读完一个单词,递增单词计数
读取下一个字符
前面有一个输入循环的模型:
while ((ch = getchar()) != STOP)
{
...
}
// wordcnt.c -- 统计字符数、单词数、行数
#include <stdio.h>
#include <ctype.h> // 为isspace()函数提供原型
#include <stdbool.h> // 为bool、true、false提供定义
#define STOP '|' //暂时选用一个文本中不常用的字符(如,|)作为输入的末尾标记。
int main(void)
{
char c; // 读入字符
char prev; // 读入的前一个字符
long n_chars = 0L;// 字符数
int n_lines = 0; // 行数
int n_words = 0; // 单词数
int p_lines = 0; // 不完整的行数
bool inword = false; // 如果c在单词中,inword 等于 true
printf("Enter text to be analyzed (| to terminate):\n");
prev = '\n'; // 用于识别完整的行
while ((c = getchar()) != STOP) //考虑循环体,用getchar()进行输入
{
n_chars++; // 统计字符
if (c == '\n')
n_lines++; // 统计行
if (!isspace(c) && !inword);
{
inword = true;// 开始一个新的单词
n_words++; // 统计单词
}
if (isspace(c) && inword)
inword = false; // 打到单词的末尾
prev = c; // 保存字符的值
}
if (prev != '\n')
p_lines = 1;
printf("characters = %ld, words = %d, lines = %d, ", n_chars, n_words, n_lines);
printf("partial lines = %d\n", p_lines);
return 0;
}
五、条件运算符:?:
-
C 提供条件表达式作为表达 if else 语句的一种 便捷方式,该表达式使用 ?: 条件运算符。
-
条件运算符是 C 语言中唯一的三元运算符(带 3 个运算对象)。
-
条件表达式的通用形式如下:
expression1 ? expression2 : expression3
如果 expression1 为真,那么整个条件表达式的值与 expression2 的值相同;
如果 expression1 为假,那么整个条件表达式的值与 expression3 的值相同。
-
举例:x = (y < 0) ? -y : y;
该语句的意思是“如果y小于0,那么x = -y;否则,x = y”。
用if else可以这样表达:
if (y < 0) x = -y;
else x = y;
六、循环辅助:continue和break
continue 和 break 语句可以根据循环体中的测试结果来忽略一部分循环内容,甚至结束循环。
6.1 continue 语句
-
3种循环都可以使用continue语句。执行到该语句时,会跳过本次迭代的剩余部分,并开始下一轮迭代。如果continue语句在嵌套循环内,则只会影响包含该语句的内层循环。
-
有两种方法可以避免使用continue,一是省略continue,把剩余部分放在一个else块中。
-
continue 的好处是减少主语句组中的一级缩进。在语句很长或嵌套较多时,提高了代码的可读性。
-
continue还可用作占位符。如,while (getchar() != '\n') ; 等同 while (getchar() != '\n') continue;
while (scanf("%f", &score) == 1) { if (score < MIN || score > MAX) { printf("%0.1f is an invalid value.Try again: ", score); continue; // 跳转至while循环的测试条件 } printf("Accepting %0.1f:\n", score); min = (score < min) ? score : min; max = (score > max) ? score : max; total += score; n++; printf("Enter next score (q to quit): "); }
6.2 break 语句
-
程序执行到循环中的break语句时,会终止包含它的循环,并继续执行下一阶段。
-
把程序中的continue替换成break,不是跳至执行下一轮循环,而是导致退出当前循环。
![]()
-
在for循环中的break和continue的情况不同,执行完break语句后会直接执 行循环后面的第1条语句,连更新部分也跳过。嵌套循环内层的break只会让程序跳出包含它的当前循环,要跳出外层循环还需要一个break:
七、 多重选择:switch和break
// animals.c -- 使用switch语句
#include <stdio.h>
int main(void)
{
char ch;
printf("Give me a char. ");
while ((ch = getchar()) != '#')
{
if ('\n' == ch)
continue;
if (islower(ch)) /* 只接受小写字母*/
switch (ch)
{
case 'a':
printf("argali, a wild sheep of Asia\n");
break;
case 'b':
printf("babirusa, a wild pig of Malay\n");
break;
case 'c':
printf("coati, racoonlike mammal\n");
break;
default:
printf("That's a stumper!\n");
} /* switch结束 */
else
printf("Please type another char or a #.\n");
} /* while循环结束 */
printf("Bye!\n");
return 0;
}
//此程序,表达式是刚输入给ch的值。然后程序扫描标签(这里指,case 'a':等)列表,直到发现一个匹配的值为止。然后程序跳转至那一行。没有匹配的标签时,如果有default :标签行,就跳转至该行;否则,程序继续执行在switch后面的语句。
7.1 switch语句
-
有时程序需要在多个选项中进行选择。可以用 if else if...else 来完成。但大多数情况用 switch 语句更方便。
-
switch语句是对紧跟在关键字 switch 后圆括号中的表达式求值。
-
程序根据 expression 的值跳转至相应的 case 标签处。然后,执行剩下的所有语句,除非执行到break语句进行重定向。如果没有case标签与expression的值匹配,控制则转至标有default的语句(如果有的话);否则,将转至执行紧跟在switch语句后面的语句。
-
如果只希望处理某个带标签的语句,就必须在 switch 语句中使用 break 语句。
-
switch的构造:
switch 在圆括号中的测试表达式的值应该是一个整数值(包括 char 类型)。
case 标签必须是整数类型(包括char类型)的常量或整型常量表达式 (即,表达式中只包含整型常量)。不能用变量作为 case 标签。
C 语言的 case 一般都指定一个值,不能使用一个范围。
switch (expression) { case label1: statement1 break;// 使用 break 跳出 switch case label2: statement2 break; default: statement3 } -
break 让程序离开 switch 语句,跳至 switch 语句后面的下一条语句。如果没有break语句,就会从匹配标签开始执行到switch末尾。
-
break 语句可用于循环和 switch 语句中,但是 continue 只能用于循环中。如果switch语句在一个循环中,continue 便可作为 switch 语句的一部分。这种情况下,就像在其他循环中一样,continue 让程序 跳出循环的剩余部分,包括 switch 语句的其他部分。
![]()
-
可以在 switch 语句中使用多重 case 标签。如,case 'a': case 'A': a_ct++;
7.2 switch和if else
-
如果是根据浮点类型的变量或表达式来选择,就无法使用 switch;
如果根据变量在某范围内决定程序流的去向,使用 switch 就很麻烦,这种情况用 if 就很方便。




浙公网安备 33010602011771号