c语言是一种结构化的程序设计语言,这里的“结构”指的就是c语言的三种逻辑结构:顺序结构,选择结构和循环结构。日常生活当中的事情其实都可以看成这三种结构的逻辑组合。那么我们该如何编程实现这些结构,让我们一起探讨。
一、if--else语句
1. if语句
if语句是c语言最常见的条件判断语句,它可以根据表达式的真假来做出逻辑判断,实现“选择”。它的语法如下:
if (表达式)
语句
如果表达式为真,则会执行下面的语句,否则这条语句就不执行。而其中的“真假”在c语言中使用0和非0表示的。0表示假,非0表示真。
以下是一个例子:
int main() { int a = 0; if(a == 0) { printf("Yes\n"); } return 0; }
上述代码中a等于0的值为真,所以输出“Yes”。
2. else语句
如果你想要在一个表达式不满足if条件的情况下执行一条语句,就需要和else语句配合使用。
if--else语句的使用方法如下:
if(表达式)
(语句块)
else
(语句块)
接下来是一个判断奇偶数的程序:
int main() { int n = 0; scanf("%d", &n); if (n % 2 == 0) { printf("是偶数\n"); } else { printf("不是偶数\n"); } return 0; }
以上程序中,如果输入的n满足if后的表达式,就会执行if后的语句,否则就会执行else后的语句。
如果if和else之后的执行语句中无大括号,则只会默认执行其后的一条语句。例如:
int main() { int n = 0; scanf("%d", &n); if (n == 1) printf("hello\n"); printf("OK\n"); return 0; }
运行结果:
无论n是否为1,“OK”都会打印在屏幕上。这是因为如果if条件为真,则会执行其后的一条语句,如果为假,就不执行。但是“OK”的打印相对于if语句是独立的,无论条件是否满足都会输出。
3. else if语句
在条件判断中,可以使用else if语句,形成多重判断。例如:
int main() { int n = 0; scanf("%d", &n); if (n == 0) { printf("输入的数字是0\n"); } else if (n > 0) //此处语法与if语句相同 { printf("输入的数字是正数\n"); } else { printf("输入的数字是负数\n"); } return 0; }
以上代码用于判断输入数字的三种情况。当有三种及以上分支条件时,我们就可以使用它。
4. 嵌套if
if语句也可以使用嵌套,来实现更加复杂的逻辑判断。例如:
int main() { int num = 0; scanf("%d", &num); if (num >= 0) { if (num % 2 == 0) printf("偶数\n"); else printf("奇数\n"); } else { printf("负数\n"); } return 0; }
当输入的数是非负数时,再判断是否是奇数或偶数。如果输入一个负数,就输出“负数”。这其中有if--else语句在另一个if语句块当中,这就构成了嵌套if语句。
5. 悬空else问题
程序中如果有多个if--else语句,则else总是和最近的if相匹配。阅读以下代码:
int main() { int a = 0; int b = 2; if (a == 1) if (b == 2) printf("hehe\n"); else printf("haha\n"); return 0; }
你可能会认为a等于0不满足条件,会执行下面的else语句输出“haha”,其实这段代码的结果是:什么都不输出。
这就是典型的悬空else问题。上述代码当中,由于第二个if存在缩进,所以让我们误以为else会与第一个if匹配,从而在不满足a==1的条件下执行else语句。但是实际上,它与离它最近的if语句匹配,a==1条件不满足,接下来的整段代码都不会执行。
为了避免上述情况,我们只需要使用大括号包含其中的语句块来体现其逻辑:
int main() { int a = 0; int b = 2; if (a == 1) { if (b == 2) printf("hehe\n"); } else { printf("haha\n"); } return 0; }
所以一般情况下,为了保持良好的代码风格和逻辑,我们在条件判断语句当中无论有多少行代码,都用大括号括起来。
二、逻辑运算符
在if--else语句的条件判断当中,常出现带有逻辑运算符的语句,接下来让我们了解各种逻辑运算符。
1. 关系操作符
c语言中用于比较的表达式就称为关系表达式,而其中所使用的操作符就是关系操作符。以下是常见的关系操作符:
> //大于 < //小于 >= //大于等于 <= //小于等于 == //等于 != //不等于
这些操作符都是双目操作符,用于比较两个数值的关系。如果满足条件,则表达式的值为1,否则为0。例如:5 > 4这个表达式的值是1,5==4的值是0。
注意:相等== 和赋值= 是两个不同的运算符,如果不慎将相等写成赋值,会出现意料之外的结果。
if (x==5) if (x=5)
第二个语句当中,不慎将相等写成了赋值,此时x被赋值为5,这个条件表达式的值就是5,5是非0,所以这个条件永远为真。
2. 条件操作符
条件操作符是一种三目操作符,能够实现类似if--else语句的逻辑分支。它的语法是:
exp1 ? exp2 : exp3
它的计算逻辑是:先判断exp1的真假。如果exp1为真,则执行exp2语句,否则执行exp3语句。整个表达式的值是最终执行语句的值。例如:
int main() { int a = 0; int b = 0; scanf("%d", &a); b = a > 5 ? 3 : -3; printf("%d\n", b); return 0; }
以上代码中,如果输入a的值大于5,b的值就是3,否则就是-3。
3. 逻辑操作符
当表达式较为复杂时,就需要使用逻辑操作符用于复杂的逻辑判断。逻辑操作符主要有三个:
1. && (逻辑与)就是并且的意思,是一个双目操作符,当其两侧的表达式都为真时,整个表达式为真。其两侧有一个表达式为假,整个表达式为假。
2. ||(逻辑或)就是或者的意思,是一个双目操作符,当其两侧的表达式有一个为真时,整个表达式为真。其两侧的表达式都为假,整个表达式才为假。
3. !(逻辑取反)是一个单目操作符,用于反转表达式的真假。
当我们要连续使用多个关系运算符时,可能会出现连用的情况。
3 < x < 5
注意:这种写法是错误的,往往会出现意料之外的结果。以上这个表达式的实际意义是:先判断3是否小于x,如果为真,则前半段的值为1,否则为0。再将1或者0与5相比较,整个表达式的值是恒为真的。这不是我们预期的效果。
对于这种逻辑判断,我们就需要使用逻辑操作符。例如:
x > 3 && x < 5
当x大于3和x小于5的条件同时满足时,整个表达式的值就是1(真)。这样就能达到预期效果。
c语言的双目逻辑运算符有一个特性:它先计算左边表达式,再计算右边表达式。如果说左边的表达式已经满足逻辑运算符的条件,那么右边的表达式不再计算。这个情况称之为“短路”。
例如:
a>=3 && a<=5
如果a<3,则左边的表达式为假,整个表达式肯定为假,右边的式子就不再计算。
a<=3 || a>=5
如果a<=3,左边的表达式就为真,整个表达式肯定为真,右边的式子就不再计算。
让我们判断以下代码的输出结果:
int main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d); return 0; }
运行结果如下:
以上代码当中,由于逻辑运算符的运算特性,先对a++进行运算。由于这是后置++,先操作再自增,所以就对a的值先进行判断。a的值为0,也就是假,整个表达式的值就是假,就不会再计算后边的两个式子。此时逻辑判断完成后,a才会进行自增运算,所以a就编程了1。而b,c,d的值都不变。
三、switch语句
除了if--else语句之外,switch语句也可以实现分支结构。当出现多重分支的情况,if--else语句的使用就会略显麻烦,switch语句可以解决这个问题。
1.switch语句与if--else语句对比
示例:判断一个数除以3后的余数
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; }
程序计算switch后的表达式,将其值与case后的数值进行比较,如果相同则执行相应的语句。这里要注意:1.switch后必须是整形表达式。2.case后必须是整形常量表达式。3.case与数字之间必须有空格。4.每一个case语句执行后,要写break。
2.switch中的break语句
如果上述代码中不写break,会发生什么情况?让我们运行代码:
结果三条语句都被执行。这是为什么呢?
原因是在switch语句中使用break才能跳出switch语句。如果某一个case语句之后没有break,程序会继续往下执行,有可能执行其他case语句中的代码,直到遇到break或者switch语句结束。所以在switch语句当中使用break才能提前其分支效果。当然,是否在每一个case语句后加入break语句也要根据实际情况而定。
3.switch语句中的default语句
在switch语句中,如果遇到所有case都无法与表达式匹配的情况,那么就要对这些情况做一些处理。这时使用default语句就恰到好处。例如:
int main() { int day = 0; scanf("%d", &day); switch(day) { case 1: case 2: case 3: case 4: case 5: printf("⼯作⽇\n"); break; case 6: case 7: printf("休息⽇\n"); break; default: printf("输⼊错误\n"); break; } return 0; }
以上代码用于判断周内的某一天是工作日还是休息日。当输入的值不再1-7的范围内时,就进入default语句,提示“输出错误”。
有人可能有以下疑问:default一定要写在最后吗?实际上,default语句的位置是随意的,不会影响程序的结果,但是一般我们为了提升代码的可读性,default语句是写在最后的。