(三)语句
从程序流程的角度来看,程序可以分为三种基本结构,即顺序结构、分支结构和循环结构,这三种基本结构可以组成所有的各种复杂程序。C语言提供了多种语句来实现这些结构,例如,通过if、switch、for、while、continue、break、return语句来实现,用来控制程序的执行。不同的控制语句有各自的规则,在不同的情况下要选择最合适的语句来进行流程控制。
1、空语句
只有分号“;” 组成的语句称为空语句。空语句是什么也不执行的语句。在程序中空语句可用作空循环体。例如:
while(getchar() != '\n');
本条语句的功能是,只要从键盘输入的字符不是回车则重新输入,这里的循环体为空语句,空语句一般有以下的几个用途:
(1)纯粹消耗CPU时间,起到延时的作用;
(2)为了程序的结构清楚,可读性好,以后扩充新功能方便。
例如:
if(xxx)
{
xxxx
}
但是企业编码规范要求
if(xxx)
{
xxxx
}
else
{
;
}
对于某些大型的软件项目,特别是一些嵌入式项目,处于自动化测试的需要,要求必须进行语句的配对。
在进行代码静态解析,单体测试case抽出的时候,为了保证全路径覆盖,很多专业的高端自动测试工具,会建议进行语句配对,此时对于一些不完备的分支,就会用空语句补全。
2、基础语句
(1)表达式语句
表达式语句由表达式加上分号“;”组成,其一般形式为
表达式;
执行表达式语句就是计算表达式的值。例如:
x = y + z; a = 520; //赋值语句
y + z; //加法运算语句,但是计算结果不能保留,无实际意义
i ++; //自增语句,i值自增1
(2)函数调用语句
由函数名,实际参数加上分号“;”组成,其一般形式为
函数名(实际参数值);
3、语句if
目前我们写的简单函数中可以有多条语句,但是这些语句总是从前到后顺序执行的,除了顺序执行外,有时候我们需要检查一个条件,然后根据检查的结果执行不同的后续代码。在C语言中可以用分支语句(Selection Statement)实现。例如:
if (x != 0)
{
printf("X is nonzero.\n");
}
其中,“x!=0”表示x不等于0的条件,这个表达式称为控制表达式,如果条件成立,则执行{}中的语句,否则不执行{}中的语句,直接跳到{}后面,if和控制表达式改变了程序的控制流程,不再按照从前向后顺序执行,而是根据不同的条件执行不同的语句,这种控制流程称为分支。
(1)布尔变量与零值比较
不可将布尔变量直接与TRUE、FALSE或者0、1进行比较
根据布尔类型的语义,零值为“假”,记作(FALSE),任何非零值都是“真”,记作(TRUE)。
假设布尔变量名字为flag,它与零值比较的标准if语句为
if(flag) //表示flag为真
if(!flag) //表示flag为假
其他的用法都属于不良风格
if(flag == TRUE)
if(flag == 1)
if(flag == FALSE)
if(flag == 0)
(2)整型变量与零值比较
应当将整型变量用“==”或者“!=”直接与0比较
假设整型变量的名字为value,它与零值比较的标准if语句为
if( 0 == value)
if(0 != value)
不能布尔类型一样。
(3)浮点变量与零值比较
不可将浮点变量用“==”或者“!=”和任何数字进行比较
千万要留意、无论是float还是double类型的变量,都有精度限制,所以一定要避免将浮点变量用" == "或者“!=”与数字进行比较,应该设法转换为“>=”或者“<=”形式。
假设浮点变量的名字为x,应当将
if ( 0.0 == x) //隐含错误的比较
转化为
#define EPSINON 0.000001
if ((x>=-EPSINON)&&(x<=EPSINON))
其中,EPSINON是允许的误差(即精度)
(ps:EPSINON是一个宏,它的值可以改成你想要的精度,通过这种方式也可以进行其他任何值的精度比较。)
(pps:由于浮点型变量的存储机制最好不要进行很大的浮点数与很小的浮点数之间进行运算,比如11111111111.000+0.00000000000001这个运算结果可能会很奇葩!)
(4)指针变量与零值比较
应当将指针变量用“==”或“!=”与NULL比较。
指针变量的零值是“空”(记作NULL)。尽管NULL的值与0相同,但是两者意义不同,假设指针变量的名字是p,它与零值比较的标准if为
if (p == NULL) //p与NULL显式比较,强调p是指针变量
if ( p != NULL)
不要写成
if(p == 0) // 容易让人误解为p是整型变量
if(p != 0)
或者
if(p) //容易让人误会p是布尔变量
if(!p)
(5)对if语句的补充说明
有时候我们可能看见"if(NULL == p)"这样的格式,这样是为了程序员不小心写漏了一个等号,变成赋值语句,这样程序不会报语法错误,而是逻辑错误,左右倒一下,就给常量赋值,这样在C语言中是不允许的,就会报语法错误。
4、跳转语句:goto
goto语句是一种无条件转移语句,与BASIC中的goto语句相似。goto语句的使用格式为:
goto 语句标号;
其中标号是一个有效的标识符,这个标识符加上一个“:”一起出现在函数内某行,执行goto语句后,程序将跳转到该标号处并执行后面的语句。另外标号必须和goto语句同处于一个函数中,但可以不在一个循环层中。通常goto语句与if条件连用,当满足某一条件时,程序跳到标号处运行。
但是goto一直一来都有争议,由于goto语句可以灵活跳转,如果不加限制,它的确会破坏结构化设计风格,goto也经常带来错误或者隐患。
使用goto时要慎重!
5、循环语句
循环结构是程序中一种很重要的结构。其特点是:在给定条件成立时,反复执行某程序段,直到条件不成立为止。给定的条件称为循环条件,反复执行的程序段称为循环体。C语言提供了很多循环语句,可以组成各种不同形式的循环结构:
- 用goto语句和if语句构成循环;
- 用while语句;
- 用do-while语句;
- 用for语句;
while语句的一般形式为
while(表达式) 语句
其中表达式是循环条件,语句为循环体。
while语句的语义是:计算表达式的值,当值为真时,执行循环体语句。
do-while语句的一般形式为
do
语句
while(表达式);
这个循环与while循环的不同在于:它先执行循环体中的与,然后判断表达式是否为真,如果为真则继续循环,如果为假终止循环,因此,do-while循环至少要执行一次循环语句。
for语句的一般形式为
for(表达式1;表达式2;表达式3)语句
它的执行过程如下:
(1)先求解表达式1。
(2)求解表达式2,若其值为真,则执行for语句中指定的内嵌语句,然后执行下面第(3)步;若其值为假,则结束循环,直接转到第(5)步。
(3)求解表达式3。
(4)转回上面第(2)步继续执行。
(5)循环结束,执行for语句下面的一个语句。
注意:
(1)for循环中的“表达式1(循环变量赋初值)”、“表达式2(循环条件)”和“表达式3(循环变量递增)”都是选择项,即可以默认,但“;”不能默认。
(2)省略了“表达式1(循环变量赋初值)”,表示不对循环控制变量赋值。
(3)省略了“表达式2(循环条件)”,则不作其他处理时变成死循环。例如:
for(i = 1;;i++)
{
sum = sum + i;
}
相当于
i = 1;
while(1)
{
sum = sum + i;
i++;
}
(4)省略了“表达式3(循环变量递增)”,则不对循环变量进行控制,这时候可以在循环体中修改控制变量,例如:
for(i = 1;i<10;)
{
sum = sum + i;
i++;
}
(5)省略了“表达式1和表达式3”。例如:
for(;i<=100;)
{
sum = sum + i;
i++;
}
(6)3个表达式全部省略:
例如:
for(;;)
分号不能省略
相当于
while(1)
(7)表达式1可以是循环变量的初值赋值,也可以是其他表达式:
for(sum = 0;i<10;i++)
{
sum = sum +i ;
}
(8)表达式1和表达式3可以是一个简单的表达式也可以是逗号表达式:
for(sum = 0,i = 1;i<100;i++)
{
sum = sum + i;
}
或者
for(i = 0,j = 100;i<100;i++,j–)
{
k = i+j;
}
(9)表达式2一般是关系表达式或者逻辑表达式,但也可以是数值表达式或字符表达式,只要其值非零,就执行循环体。
for(i = 0;(c= getchar())! = '\n';i+=c);
又如:
for(;(c = getchar())!='\n';)
{
printf("%c",c);
}
循环语句的效率
C语言循环语句中,for语句使用频率最高,while语句其次,do语句很少用,本节重点讲循环体的效率,通过循环体效率的基本方法是降低循环体的复杂性。
在多重循环中,应该将最长的循环放在最内层中,最短的循环体放在最外层中,以减少CPU跨切循环层的次数。
6、break和continue
1、break语句
break语句通常在循环语句和开关语句中,当break用于开关语句switch时,可使程序跳出switch而执行switch以后的语句;如果没有break语句,则成为一个死循环而无法退出。
当break语句用于do-while、for、while循环语句时,可使得程序终止循环而执行循环后的的语句,通常break语句总是与if语句联系在一起,即满足条件时便可以跳出循环。
注意:
- break语句对if-else 的条件语句不起作用;
- 在多层循环中,一个break语句只向外跳一层。
2、continue语句
continue语句的作用是跳过循环体中剩余的语句而强行执行下一次循环。continue语句只用在for、while、do-while等循环体中,当与if条件语句一起使用,用来加速循环。
7、switch语句
switch语句是多分支选择语句,而if语句只有两个分支可以选择,虽然if可以嵌套,但是那样的程序比较冗长。
switch的格式为:
switch (value)
{
case 1:
{
break;
}
case 2:
{
break;
}
default:
{
break;
}
}
(1)每个case语句的结尾不要忘记加break,不然会继续执行下一个case;
(2)不要忘记加default分支。