目录
c语言是一种结构化的程序设计语言,它的结构主要分为顺序、选择(分支)、循环。日常的所有事情都可以拆分成这三种结构。顺序结构就不用过多介绍了,就是按照先后顺序一条一条地执行命令。接下来主要详细介绍选择结构和循环结构。
一、选择结构
选择结构又叫分支结构,在C语言中可以使用if语句、switch语句实现。它的逻辑结构大致如下:
图上只是画了3个分支,分支可以是1个也可以是很多个,根据设置的条件选择执行哪个分支到终点。
1.1、if语句
(1)if语句
if语句的语法形式如下:
if(表达式)
一条语句;
if(表达式){
有多条语句的代码块
}
当if语句的代码块内只有一条语句时,{}可以省略;当有多条语句时,必须有{},这样编译器才知道代码块是从哪里开始和结束的。包括后面的if-else语句、嵌套的if语句、for语句、while语句都是这样的规则。虽然省略{}能使代码更简洁,但是不易理解、易出错,在本章节的 (3) 嵌套的if语句中,它的劣势就明显展现出来。
if语句的逻辑是表达式为真(0)就执行,表达式为假(非0)就不执行。其流程图如下:
(2)if-else语句
if-else语法形式如下:
if(表达式){
代码块1
}
esle{
代码块2
}
if-else的逻辑是表达式为真执行代码块1,为假则执行代码块2。其流程图如下:
(3)嵌套的if语句
代码块内能嵌套其它的if语句,else能跟if语句连用,嵌套不限数量,想嵌套多少层都可以。以嵌套2层为例,其语法形式如下:
if(表达式1){
代码块1
}
else if(表达式2){
代码块2
}else if{表达式3}{
代码块2
}
// 也可以换一种写法,让else与if不连用
if(表达式1){
代码块1
}
else{
if(表达式2){
代码块2
}
else{
if(表达式3){
代码块3
}
}
}
流程图如下:
接下来看看下面的代码,执行结果是多少?
进入if语句,因为a不等于1,所以执行else语句,结果打印了"嘿嘿"。如果你是这样想的那就错了。这就是不加{}的弊端,造成else的悬空问题(else语句与预期的if语句不匹配),认为else与第一个if对齐就是跟第一个if匹配。实际上else语句与if语句的匹配符合就近原则(前提条件是if和else在同一层嵌套中),如上图中的else是跟上面更近的if(a==0)匹配,这个if-else语句是嵌套在第一个if语句里面的。所以程序的执行结果应该是打印"呵呵!",如下图验证:
加上{}让代码逻辑更清晰、易于理解。从这个例子我们能得到启发,良好的代码规范能让团队协作效率更高,减少Bug的出现,在这里我推荐大家看一本书《高质量的C/C++编程指南》,里面的 第2章程序的版式 和 第3章命名规则 详细地讲述了C/C++编程规范,建议大家有时间好好读读。
1.2、关系、条件、逻辑操作符
选择结构和循环结构的表达式中通常会有各种用于判断的操作符,下面将介绍这些操作符。
(1)关系运算符
用于比较的表达式就是关系表达式,里面的操作符就叫关系运算符。主要有下面6个:
>:大于
<:小于
>=:大于等于
<=:小于等于
==:等于(区别于赋值运算符=)
!=:不等于
关系表达式的返回值为0(真)或者1(假),比如 1>2 为假,返回值为0。有时候因为疏忽,会把关系表达式中的关系运算符等于==写成赋值运算符=,比如:
上面代码把3赋值给x,x为非0值,表达式为真,执行了打印,这是我们不期望的结果。为了防止漏写=,可以养成把变量写在后面的习惯,如下:
这样运行时就会报错,便于我们发现错误。报错的原因是:不能把一个值赋值给常量,常量的值是不能改变的。
关系运算符不建议连用,比如我们想判断j大于i并小于k,想连用关系运算符然后这样写:
i<j<k
事实上关系运算符是从左到右计算的,先计算i<j得到结果result,再计算result<k,得到最终结果。所以不建议连用关系运算符,这样会导致代码不易理解、易出错。我们可以这样写:
j>i && j<k
(2)条件运算符
条件运算符又叫做三目运算符,有三个操作数,语法形式如下:
表达式1 ? 表达式2 : 表达式3
它的流程图是:
(3)逻辑运算符
逻辑运算符的功能是进行逻辑判断,用于构造更复杂的表达式,有以下3个:
!:非
语法形式:!表达式
解读:表达式为真,返回0;表达式为假,返回1。
&&:与
语法形式:表达式1 && 表达式2
解读:只要有一个表达式为假,返回0;表达式1和表达式2都为真,返回为1。
||:或
语法形式:表达式1 && 表达式2
解读:只要有一个表达式为真,返回1;表达式1和表达式2都为假,返回为0。
逻辑运算符是先计算左边的表达式,再计算右边的表达式。因此在有些情况下,只要判断了左边的表达式就能知道整个表达式的返回值,这种计算方法被称为短路求值。如:
对于:表达式1 && 表达式2
如果:表达式1为假,那么整个表达式为假,不必再继续判断。
对于:表达式1 || 表达式2
如果:表达式1为真,那么整个表达式为真,不必再继续判断。
1.3、switch语句
if语句能改写成switch语句,但是switch语句比if语句更易用、可读。它的语法形式如下:
switch(表达式){
case 值1:代码块1
case 值2:代码块2
......
defualt:代码块3
}
switch语句根据表达式的返回值,选择case分支,并执行相应分支后的语句;如果没有对应的case分支,就执行defualt后面的语句。
注意:表达式的返回值只能是整数,case 后面的值只能是常量整数。另外,在执行完对于case分支后的代码块后,要加上一个break;,这样才会跳出siwtch语句,而不是接着执行后面的case分支后的代码块。比如下面的例子:
上面的程序中,switch语句跳转到case 1分支后,执行了后面的所有语句,我们不期望这样。解决办法,加上break;。结果如下:
二、循环结构
在C语言中循环结构可以用for语句、while语句、do-while语句实现。它的逻辑结构大致如下:
根据设置的条件,决定执行多少次循环体。
2.1、while语句
语法形式如下,跟if语句很像:
while(表达式){
代码块
}
它的流程图:
continue和break语句可以在代码块中间位置,一旦碰到就无条件转向。continue表示跳过本次循环中continue语句后面的代码块里的语句;break表示直接退出循环,终止循环。
我们来看一个使用while语句的例子:
因为a的值没改变一直小于5,所以会进入死循环,退不出循环。想退出循环,在循环体内必须有对表达式里的变量进行调整的语句或者有其它的转向语句(break、goto等),如下面这个例子,对变量进行了调整:
2.2、for语句
for语句的语法形式如下:
for(表达式1; 表达式2; 表达式3){
代码块
}
它的流程图如下:
while语句打印1~10改写成用for语句:
相较于while语句和do-while语句,for语句的初始化、控制、调整三部分更加集中,更易理解和代码维护,所以for语句是三种循环中最常用的。
注意,for语句的continue,是跳转执行调整部分的表达式,而不是初始化部分。
2.3、do-while语句
do-while语句在三种循环语句中使用得最少,它的语法形式如下:
do{
代码块
}while(表达式)
它的流程图如下:
从上面的流程图可以看出它相较于其它两个循环语句的特点:do-while语句先执行代码块,再进行表达式判断;而for、while语句是先进行表达式判断,再执行代码块。因此,while语句至少要执行一次代码块,适用于至少要执行一次的场景。比如下面的应用场景:
num值为0时,有1位数字。如果使用for或者while语句,先进行表达式判断,则一次cnt计数器增加1都没有执行,最后打印结果会是0。因此这种情况用do-while语句实现更方便。
最后需要注意continue语句的一个点,循环中调整的部分不要放在continue语句后面,不然一遇到continue就结束本轮循环,不执行后面的调整部分,同样也会造成死循环。
2.4、循环的嵌套
这三种循环语句都是可以互相嵌套的,嵌套的循环能更好地解决一些问题,下面举个例子。
问题:找到1~100之间的所有素数(只能被1和本身整除)并打印出来。
代码:
这种素数求解的方法叫试除法,其实还能对上面的方法进行优化,把判断能否被2~ i - 1之间的数整除,改成2 ~ 。原因如下:
比如判断 i 为16是不是素数:
16 = 4 * 4
= 2 * 8
= 1 * 16
我们会发现将16表示为 a * b,a和b中总有一个数小于等于。现在将16换成 i ,因此我们只需要判断 i 能不能被小的那个整数整除,就能知道 i 是不是素数,没必要再遍历 以后的整数了。
故可以把上面代码中的控制表达式 j < i 改成 j <= sqrt(i)进行优化。sqrt是一个用于开非负数平方的库函数,定义在头文件<math.h>中。素数的更多解法,可搜索文章《素数求解的N种境界》。
三、无条件转向语句goto
goto语句能实现在同一函数内跳转到标签的位置,标签名是自己取的,语法形式如下:
function(){
语句
...
goto next;
语句
...
next:
语句
}
如上,next是自己取的标签名 goto next; 执行后,跳转到标签next,执行next: 之后的语句。
goto语句不建议使用过多,因为过多的任意跳转,会打乱程序的结构性,导致程序杂乱无章。但是在多层循环嵌套中使用goto语句退出最外层循环是很方便的,如下为代码所示:
for(){
for(){
for(){
if(disaster)
goto error;
}
}
}
error:
......
循环嵌套中,如果不用goto语句,使用break语句一层层退出是比较麻烦的。
最后,我们来做一个小练习:
题目:电脑将在一分钟内关机,如果输入"我是猪",则终止关机。
代码:
不能用==判断字符串的原因是,ch指向的是字符串的首地址,而不是字符串的内容,所以要用strcmp函数比较两个字符串,返回0表示相等,返回值大于0表示第一个字符串的ASCII码值大于第二个字符串,返回值小于0表示第一个字符串的ASCII码值小于第二个字符串。
标签:语句,代码,else,运算符,while,循环,表达式,分支 From: https://blog.csdn.net/2401_86272648/article/details/140588179