【C-Primer-Plus读书笔记】第7章:C控制语句:分支和跳转
if语句
if
语句被称为分支语句或选择语句,因为它相当于一个交叉点,程序要在两条分支中选择一条执行。if
语句(单分支)的通用形式如下:
if( expression )
statement
如果对expression求值为真,则执行statement;否则,跳过statement。statement可以是一条简单语句或复合语句。
if else语句
C还提供了if else
形式,可以在两条语句之间作选择。if else
(双分支)语句的通用形式如下:
if( expression )
statement1
else
statement2
如果对expression求值为真,则执行statement1;否则,执行statement2。statement1和statement2可以是一条简单语句或复合语句。
另一个示例:介绍getchar()和putchar()
下面讲解一对字符输入/输出函数:getchar()
和putchar()
getchar()
函数不带任何参数,它从输入队列中返回下一个字符。如:`ch = getchar();` 等价于 `scanf("%c", &ch);`
putchar()
函数打印它的参数。如:`ch = putchar(ch);` 等价于 `printf("%c", ch);`
由于这些函数只处理字符,所以它们比更通用的
scanf()
和printf()
函数更快、更简洁。
ctype.h系列的字符函数
C有一系列专门处理字符的函数,ctype.h
头文件包含了这些函数的原型。这些函数接受一个字符作为参数,如果该字符属于某特殊的类别,就返回一个非零值(真);否则,返回0(假)。isalpha()
函数监测一个字符是否是一个字母
ctype.h
头文件中的字符测试函数
函数名 | 如果是下列参数时,返回值为真 |
---|---|
isalnum() | 字母数字 |
isalpha() | 字母 |
isblank() | 标准的空白字符或任何其他本地化指定为空白的字符 |
lscntrl() | 控制字符,如Ctrl+B |
isdigit() | 数字 |
isgraph() | 除空格之外的任意可打印字符 |
islower() | 小写字母 |
isprint() | 可打印字符 |
ispunct() | 标点符号 |
isspace() | 空白字符 |
isupper() | 大写字母 |
isxdigit() | 十六进制数字符 |
ctype.h
头文件中的字符映射函数
函数名 | 行为 |
---|---|
tolower() | 如果参数时大写字符,返回小写字符,否则返回原始参数 |
toupper() | 如果参数时小写字符,返回大写字符,否则返回原始参数 |
- 多重选择else if
实际上,else if
是已学过的if else
语句的变式。即可以用多个if else
语句嵌套达到同样的效果,但是这种代码不清晰,容易产生混乱,不易维护。
if else
(多分支)语句的通用形式如下:
if( expression1 )
statement1
else if( expression2 )
statement2
//...
else
statement3
如果对expression1求值为真,则执行statement1;或者对expression2求值为真,则执行statement2;否则,执行statement3。statement1、statement2和statement3可以是一条简单语句或复合语句。
- else与if配对
规则是:如果没有花括号,else
与离它最近的if
匹配,除非最近的if
被花括号括起来。记住,编译器是忽略缩进的,缩进只是为了人类能更清晰的看懂代码结构。 - 多层嵌套的if语句
有时,选择一个特定选项后又引出其他选项,这种情况可以使用另一种嵌套if
。
逻辑运算符
逻辑运算符 | 含义 | ||
---|---|---|---|
&& | 与 | ||
\ | \ | 或 | |
! | 非 |
- 备选拼写:iso646.h头文件
C99新增了可代替逻辑运算符的拼写,它们被定义在ios646.h
头文件中:
传统写法 | iso646.h | ||
---|---|---|---|
&& | and | ||
\ | \ | or | |
! | not |
- 优先级
!
运算符的优先级很高,比乘法运算符还高,与递增运算符的优先级相同,只比圆括号的优先级低。&&
运算符的优先级都比||
运算符高,但是两者的优先级都比关系运算符低,比赋值运算符高。 - 求值顺序
C保证逻辑表达式的求值顺序是从左到右。&&
和||
运算符都是序列点,所以程序在从一个运算符对象执行到下一个运算符对象之前,所有副作用都会生效。而且,C保证一旦发现某个元素让整个表达式无效,便会立即停止求值。 - 范围
&&
运算符可用于测试范围。例如:
if (range >= 90 && range <= 100){}
if (ch >= 'a' && ch <= 'z'){}
条件运算符:?:
C提供条件表达式作为表达if else
语句的一种便捷方式,该表达式使用?:
条件运算符。该运算符分为两部分,需要3个运算对象,所以称为三元运算符。
条件运算符是C语言中唯一的三元运算符。条件表达式的通用形式如下:
expression1 ? expression2 : expression3
如果expression1为真,那么整个条件表达式的值与expression2的值相同;否则,整个条件表达式的值与expression3的值相同。
通常,条件运算符完成的任务用if else
语句也可以完成。但是,使用条件运算符代码更简洁,而且编译器可以生成更紧凑的程序代码。
循环辅助:continue和break
一般而言,程序进入循环后,在下一次循环测试之前会执行完循环体中的所有语句。continue
和break
语句可以根据循环体中的测试结果来忽略一部分循环内容,甚至结束循环。
- continue语句
continue语句让程序跳过循环体后续的代码,进入下一轮迭代(即跳转至对循环的测试表达式求值);continue也可作占位符,比如空循环体(什么都不做)。 - break语句
break语句会终止包含它的循环(亦可理解为跳出循环),并继续执行下一阶段。如果break语句位于嵌套循环内,它只会影响包含它的当前循环。
多重选择:switch和break
对应if else if...else
语句,还有一种更方便简洁的语法,即switch
语句。
switch
语句的通用形式如下:
switch (expression)
{
case 常量1:
statement1
break;
case 常量2:
statement2
break;
default:
statement
}
要对紧跟在关键字switch
后圆括号中的表达式求值,然后程序扫描标签(即 case
)列表,直到发现一个匹配的值为止,然后执行该标签下的statement。如果没有匹配项,则执行default
标签下的statement,而没有default
标签,就直接结束switch语句继续执行后续语句。break
语句让程序离开switch
语句,跳至switch
后的下一条语句,如果没有break
语句,程序会从匹配标签开始执行到switch
末尾。
break
语句可用于循环和switch
语句中,但是continue
只能用于循环中。当两种语句发生嵌套关系,注意其产生影响的对应语句。
- 只读每行的首字符
通常,只读每行的首字符后需要丢弃该行其他字符,可以用下面的代码实现这样的行为:
while(getchar() != '\n')
continue;
而对于空行(用户一开始就按下Enter键)可以这样:
if(getchar() == '\n')
continue;
- 多重标签
可以使用多重标签来执行同一个语句,如:
switch (expression)
{
case 常量1_1:
case 常量1_2:
statement1
break;
case 常量2_1:
case 常量2_2:
statement2
break;
default:
statement
}
由于前一个标签没有关联break语句,所以程序流直接执行下一标签的语句。
- switch和if else
- 如果是根据浮点类型的变量或表达式来选择,就无法使用switch,switch只针对整型。
- 如果根据变量在某范围内决定程序流的去向,使用switch就很麻烦,这种情况用if更合适。
- switch通常运行快一些,生成的代码少些。
goto语句
goto
语句有两部分:goto和标签名。标签的命名遵循变量命名规则,如下:
goto part2;
//上述goto语句跳转至下面
part2:printf("hello world\n");
避免使用goto,过度使用goto语句会让程序错综复杂!即使没有goto语句,上面所学的分支跳转语句完全够用。