c语言是结构化的程序设计语言,它分为三大结构,分别是是顺序结构、选择结构、循环结构。其中顺序结构是最简单的结构,没多少可讲的,所以本篇我重点来介绍选择结构。 我们可以使⽤ if 语句、switch语句 实现分⽀结构,下面我将详细解析这两种语句。
目录
1. if语句
1.1 if与else
1.1.1 基本句型
一、最简单的句型:
1 if(表达式)
2 语句;
在C语⾔中,0为假,⾮0表⽰真。 所以在if语句中,表达式的结果如果是0,则语句不执⾏,表达式的结果如果不是0,则语句执⾏。
例⼦1:输⼊⼀个整数,判断是否为奇数(不用判断是不是偶数)
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num % 2 == 1)
printf("%d 是奇数\n", num);
return 0;
}
该程序的执行逻辑是这样的:
如果⼀个数不是奇数,那就是偶数了,如果任意⼀个整数,我们要清楚的判断是奇数还是偶数怎么表示呢?这⾥就需要 if...else... 语句了,语法形式如下:
二、基本句型:
1 if(表达式)
2 语句1;
3 else
4 语句2;
例子1的延续: 输⼊⼀个整数,判断是否为奇数,如果是奇数打印是奇数,否则打印数偶数。
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num % 2 == 1)
printf("%d 是奇数\n", num);
else
printf("%d 是偶数\n", num);
return 0;
}
1.1.2 分⽀中包含多条语句
if语句默认只能控制一条语句。如果要控制多条语句,则需要用 { } 把代码括起来。(else语句也是如此)
举例:
//没有{} //有{}
左边因为if语句默认控制一条语句,所以即使a不是1,程序还是执行了printf("abc")。
而右边用 { } 括起来后,if语句把下面两条语句都控制住了,所以什么也没有打印。
所以我们有了这种句型:
if(表达式)
{
…… //多条语句
}
else
{
…… //多条语句
}
1.1.3 悬空else问题 (if与else的配对)
就近原则:如果有多个 if 和 else , else 总是跟最接近的 if 匹配。
我们从下⾯的代码开始讲解:
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
if(b == 2)
printf("你好\n");
else
printf("hello\n");
return 0;
}
运行结果是什么?
- 很多初学者一上来就认为,上边的 if与else在同一条竖直线上,所以就认为它们是配对的。然后发现a是0不是1,不会执行“if(b == 2)”的代码,所以认为最终结果是打印“hello”。
但是这样想是错的,让我们看看最终结果:
结果是什么都没有打印。这说明else没有跟同在竖直线的 if(a == 1) 配对,而是跟最近的 if( b == 2) 配对,这满足就近原则。 把代码写成这样就好理解了:
int main()
{
int a = 0;
int b = 2;
if (a == 1)
{
if (b == 2)
printf("你好\n");
else
printf("hello\n");
}
return 0;
}
1.1.4 else if 句型的演变
- 在if语句中,if( ) 可以与 else if( ) 连用,构成多重判断。
else if句型: //……省略号处表示多条语句
if(表达式1)
{ …… }
else if(表达式2)
{ …… }
else
{ …… }
但是else if句型是怎么来的呢? 我们从一个例子寻找答案:输入一个整数,判断它是0,还是正数或者负数
int main()
{
int n = 0;
scanf("%d", &n);
if (n == 0) //0是正数与负数的分割点
printf("输入的是0");
else //n不是0时,要进一步判断
{
if (n > 0)
printf("输入的是正数");
else
printf("输入的是负数");
}
}
if(表达式)
语句1;
else
语句2;
补充说明:if内部与else内部都只有一条语句时 ,那么这一整个“if……else……”都只是一条语句,而不是多条语句。
既然整个“if (n > 0) printf("输入的是正数"); else printf("输入的是负数");”都是一条语句,那我们可以把上面的代码省去一个{},缩写成如下形式:
int main()
{
int n = 0;
scanf("%d", &n);
if (n == 0) //0是正数与负数的分割点
printf("输入的是0");
else //n不是0时,要进一步判断
if (n > 0)
printf("输入的是正数");
else
printf("输入的是负数");
}
我们发现第一个else与 if(n > 0) 之间隔了多个空格,而空格属于空白字符,所以一个空格 和 多个空格的作用是一样的。我们把多余的空格删去,就得到了最简便的版本。
这就是else if的演变过程。
1.2 关系操作符
C 语⾔的 关系表达式 中,⾥⾯使⽤的运算符就称 为“关系运算符”(relational operator),主要有下⾯6个。// if()中的表达式是可以进行运算的
- > :⼤于运算符
- < :⼩于运算符
- >= :⼤于等于运算符
- <= :⼩于等于运算符
- == :相等运算符
- != :不相等运算符
注意:相等运算符 == 与 赋值运算符 = 是两个不⼀样的运算符,不要混淆。有时候,可能会不小心写出下面的代码,它可以运⾏,但会出现意料之外的结果。
按理来说,x是等于0的,并不会输出“x是3”这句话,但是为什么会这样呢? 原因是这里使用了赋值运算符=,使得x被赋值成3,所以表达式的值最终为3, 而非0代表真,所以程序执行了 “printf("x是3");” 这条语句。改回相等运算符 == 就没事了:
为了防止出现这种错误,我们可以将变量写在等号的右边。
如 if (3 == x) ...
1.3 条件操作符(三目运算符)
条件操作符也叫三⽬操作符(这是C语言唯一一个三目运算符),需要接受三个操作数的,形式如下:
exp1 ? exp2 : exp3 // exp表示 表达式
整个条件运算符(exp1 ? exp2 : exp3)运算完后会返回一个值。假设 m =(exp1 ? exp2 : exp3),下面给出m的结果。
条件操作符的计算逻辑是:如果 exp1 为真, exp2 计算,计算的结果是整个表达式的结果;如果 exp1 为假, exp3 计算,计算的结果是整个表达式的结果。
用 if 语句展示 ( b = a>5 ? 3 : -3)的计算逻辑:
if (a > 5)
b = 3;
else
b = -3;
1.4 逻辑判断
1.4.1 逻辑操作符
逻辑运算符提供逻辑判断功能,⽤于构建更复杂的表达式,主要有下⾯三个运算符。
- ! :逻辑取反运算符 (改变单个表达式的真假) 。
- && :与运算符,就是并且的意思(两侧的表达式都为真,则为真,否则为假)。
注意 :在c语音中,表示某个变量在两个数之间时,如1 < x <2 ,不能真的写成数学上的形式, 而是写成这样 (1 < x && x < 2) 。
- || :或运算符,就是或者的意思(两侧⾄少有⼀个表达式为真,则为真,否则为假)。
1.4.2 经典习题:闰年判断
输⼊⼀个年份year,判断year是否是闰年
闰年判断的规则:
- 能被4整除并且不能被100整除是闰年
- 能被400整除是闰年
版本1:
int main()
{
int year = 0;
scanf("%d", &year);
if (year % 4 == 0 && year % 100 != 0)
printf("是闰年\n");
else if (year % 400 == 0)
printf("是闰年\n");
return 0;
}
我们用 或运算|| 来取代 “if…else if…”可以简化代码:
版本2:
int main()
{
int year = 0;
scanf("%d", &year);
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
printf("是闰年\n");
return 0;
}
1.4.3 短路问题
C语⾔逻辑运算符有⼀个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是保证的。
如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式进行运算。这种情况称为“短路”。
&&的短路:左边为0
在逻辑与 中,当左边的表达式已经为假时,右边的表达式不再运算。
|| 的短路:左边为1
在逻辑或 中,当左边的表达式已经为真时,右边的表达式不再运算。
2.switch语句
除了 if 语句外,C语⾔还提供了 switch 语句来实现分⽀结构。 switch 语句是⼀种特殊形式的 if...else 结构,⽤于判断条件有多个结果的情况。它把多重 的 else if 改成更易⽤、可读性更 好的形式。
switch (表达式)
{
case value1: //value为整数值
……(语句)
break;
case value2:
……(语句)
break;
default:
……(语句)
}
上⾯代码中,根据表达式不同的值,执⾏相应的 case 分⽀。如果找不到对应的值, 就执⾏ default 分⽀。
注意:
- switch 后的表达式(exp)必须是整型表达式。
- case 后的值,必须是整形常量表达式。(如:1、4、1+3、2*3)
- 每⼀个 case 语句中的代码执⾏完成后,需要加上 break,才能跳出这个switch语句。
- 关键字switch和case是必需的,关键字break和default是非必需的 (后面会讲)
2.1 if语句和switch语句的对⽐
例子:输⼊任意⼀个整数值,计算除3之后的余数
用 if 语句来实现这样的:
int main()
{
int n = 0;
scanf("%d", &n);
if (n % 3 == 0)
printf("整除,余数为0\n");
else if (n % 3 == 1)
printf("余数是1\n");
else
printf("余数是2\n");
return 0;
}
而用 switch语句实现是这样的:
int main()
{
int n = 0;
scanf("%d", &n);
switch (n % 3)
{
case 0:
printf("整除,余数为0\n");
break;
case 1:
printf("余数是1\n");
break;
case 2:
printf("余数是2\n");
break;
}
return 0;
}
2.2 省去break的switch语句
在前面的代码中,如果我们把所有情况(case)的break都去掉,会发生什么呢?
明明3除以3的余数是0,为什么会把 “余数是1” 和 “余数是2” 都打印出来了呢?
只有在 switch 语句中使⽤ break 才能在跳出 switch 语 句,如果某⼀个 case 语句的后边没有 break 语句,代码会继续玩下执⾏,有可能执⾏其他 case 语句中的代码,直到遇到 break 语句或者 switch 语句结束。
所以该代码从case 0进去,一直执行完case 2的内容才结束。
更通俗的讲,如果我们 把case看作一个房间的入口,把break看作房间的出口,把switch表达式的值看作房间的门牌号。那么当没有出口break时,上下相邻的两个房间是连通的,直到走完整个switch语句才算离开。
2.3 default与case的顺序问题
switch后的表达式中的值 ⽆法匹配 case语句 的时候,这时候要不就不做处理,要不就得在 switch 语句中加⼊ default ⼦句。
default 可以处理 case 外的情况,那default一定要放在最后吗?
答案是否定的,default 语句是没有顺序要求的,只要你的顺序是满足需求的就可以。
不过我们通常是把 default ⼦句放在最后处理的。
这里可以看出,default 内部没有break的话也是一直往下执行代码,直到遇到其他地方的case或者switch语句结束才离开。
同样的,case后的整形常量表达式也是没有顺序要求的。
好了,C语言的分支结构我已经讲完了,你学会了吗
下一期我将会讲解c语言的循环结构,下期见~~