[深入浅出C语言]浅析控制语句(前篇)

110 阅读9分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

前言

        本文为C语言控制语句的第一篇,主要介绍了控制语句中的if...else和switch语句,内容不多,实际上关于控制语句的话还有循环语句和转向语句没讲,打算下一篇再讲讲,可以期待一下哦。

        由于笔者水平有限,文章拙劣而纰漏难免,欢迎指正,希望于你有益。

C语句可分为以下五类:

  1. 表达式语句

  2. 函数调用语句

  3. 控制语句

  4. 复合语句

  5. 空语句

而本文主要讲讲控制语句。


控制语句总览

      控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成,C语言有九种控制语句。

可分成以下三类:

 1. 条件判断语句也叫分支语句:if语句、switch语句;

 2. 循环执行语句:do while语句、while语句、for语句;

 3. 转向语句:break语句、goto语句、continue语句、return语句。


分支语句

if语句

      在C中非零为真,0为假。为什么叫分支语句呢?只要if()括号里的表达式为真,就会执行对应代码,如果还有else语句的话,表达式为假时就不执行if()后面语句,而执行else后面的语句,有点像是如果xxx就xxx不然就xxx,也就像是岔路口多条分支一次只能决定一条分支的路线。

if(exp1)//exp是表达式
{
    //...可以是各种语句
}
else if(exp2)
{
    //...可以是各种语句
}
//...还可以有多个else if语句,相当于树多个分支
else
{
    //...可以是各种语句
}

image.png

例题剖析

例题1

为什么啥也不输出呢?

image.png

注意了,if…else…算一条语句,而且else与上面离得最近的if配对,但如果有花括号相隔的话就不一样了。

image.png

image.png

即使把缩进改了也没有影响,最多影响自己读程序罢了。

image.png

      善用缩进让代码对齐,利于代码的阅读理解,是良好代码风格的体现,不过也要注意单单缩进不会影响程序运行。

例题2

      看看哪一种写法更好一些。

image.png

        代码1什么意思呢,如果condition为真就返回1否则返回0,其实执行起来和代码2没区别,但是在读代码的时候可能会觉得是无论if内是否执行最后都要执行return 0;,忽视了return直接结束当前函数的作用。

        其实把return语句换掉就不一样了:

image.png

      管你if执不执行都会执行x = 5;

      所以代码2逻辑更加清晰明了,不需要去估测,是什么就是什么。

例题3

      再看看下面代码,写哪个更好一些?

image.png

      按代码3的写法,如果漏写了一个等号,程序有可能照常运行不报错,但是这个错误有可能会影响程序逻辑,产生语义错误(简单来说就是你想的逻辑和你写出来程序的运行逻辑出现差异),关键是编译器不报错找出问题的难度大大增加了,你有可能都不会想到是这一个地方的小问题影响到整个程序的逻辑,费时费力去纠错还不一定能解决问题。

1541405861-5374-img.png

        而按代码4的写法,如果漏写了一个等号,编译器马上就给你报错,一下就找到问题所在,并且可以防微杜渐。莫要到为时晚已积重难返,明明有bug就是找不出来。

image.png

        对于代码3和代码4的探讨针对的是左边是不是单个变量,选用代码4风格目的是为防止由逻辑表达式变成赋值表达式,并不是说if()内的条件都要把常数放左边。

        如果待比较的值是常量,可以把该常量放在左侧有助于编译器捕获错误。

        因为C语言不允许给常量赋值,编译器会把赋值运算符的这种用法作为语法错误标记出来,许多经验丰富的程序员在构建比较是否相等的表达式时,都习惯常量放在左侧,还不赶快用起来!

switch语句

        当switch()括号内的表达式的值满足case时,执行case后面的语句,只要满足就执行,除非遇到break跳出switch(), 可以加上default语句,当所有case不满足时,会执行default语句。

switch(整型表达式)
{  

 语句项;

}

语句项就是一些case语句,比如:

switch(day)
{
    case 1:
        x = 10;
}

switch必须搭配break才能真正实现分支,没有break的话万一有两个及以上的case满足会把它们后面的语句都执行,压根起不到分支作用。

image.png

        如果表达的值与所有的case标签的值都不匹配怎么办?

        其实也没什么,结果就是所有的语句都被跳过而已。

        程序并不会终止,也不会报错,因为这种情况在C中并不认为是个错误。

        但是,如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢? 你可以在语句列表中增加一条default子句,把下面的标签 default: 写在任何一个 case 标签可以出现的位置。

        当 switch 表达式的值并不匹配所有 case 标签的值时,这个 default 子句后面的语句就会执行。 所以,每个switch语句中只能出现一条default子句。 但是它可以出现在语句列表的任何位置,而且语句流会像执行一个case标签一样执行default子句

        在每个 switch 语句中都放一条default子句是个好习惯。

注意事项

  1. switch可以嵌套。

  2. case:后面非break语句可以不止一条。

  3. break语句在switch一次只能跳出一层switch,而且只能是目前所在的switch。

  4. switch()括号内整型变量,整型常量,整型表达式都可以,不过不要放入布尔表达式,也就是判断表达式,比如flag == 1之类的,因为这类表达式的值只有两种:0和1,而case取值可能有很多种。

  5. 多个case对应一条执行语句,也就是在多种取值情况下执行同一条语句。

int main()
{
    int day = 6;
    switch (day)
    {
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
            printf("周内\n");
            break;
        case 6:
        case 7:
            printf("周末\n");
            break;
        default:
            printf("bug!\n");
            break;
    }
    return 0;
}

        一般来说都要记得在case后面加上break语句,除非特意如此。

        最好最后带上一个default语句,以便在所有条件都不满足的情况下进行响应或说明。

  1. 如果多个不同case匹配,想执行同一个语句,可以像上面的代码那样省掉一些break语句,不过其实也可以这样:
case 1:
    printf("星期一\n");
    printf("星期一\n");
    printf("星期一\n");
    printf("星期一\n");
    break;

        把语句都放在一个case后面执行,因为case一旦满足会一直执行,遇见break则停下。

        那你看这样行不行呢?

case 1:
    int a = 10;
    printf("星期一\n");
    printf("星期一\n");
    printf("星期一\n");
    break;

不行!

注意:不能在case和break之间定义变量,除非放在代码块里面

        比如:

case 1:
{
    int a = 10;
    printf("星期一\n");
    printf("星期一\n");
    printf("星期一\n");
}
break;

其实case后面要放入多条语句的话最好都封装到函数里面去。

  1. case后面必须得是整型的常量或常量表达式,那么case 语句后面是否可以是const修饰的只读变量呢?

答案是:不行

        比如:

int main()
{
	const int a = 10;
	int b = 10;
	switch (b) {
	case a: //不行
		printf("hello\n");
		break;
	default:
		break;
	}
	return 0;
}
  1. 建议按执行频率排列case语句,把最常执行的情况放在前面而把最不常执行的情况放在后面。

        最常执行的语句如果放在后面的话找起来可能会比较困难,而放在前面可以很快找到。

  1. 将default子句只用于检查真正的默认情况

        有时候,你可能剩下了最后一种情况需要处理,于是就决定把这种情况用default子句来处理,这样也许会少写一些代码,但是这样不太明智。

        因为这样将失去case语句的标号所提供的自说明功能,而且也丧失了使用default子句处理错误情况的能力。

        应当把每一种预期的情况都用case语句来完成,而把真正的默认情况也就是错误情况的处理交给default子句。

        比如:

原版

int main()
{
    int day = 6;
    switch (day)
    {
        case 1:
            printf("周一\n");
            break;
        case 2:
            printf("周二\n");
            break;
        case 3:
            printf("周三\n");
            break;
        case 4:
            printf("周四\n");
            break;
        case 5:
            printf("周五\n");
            break;
        case 6:
            printf("周六\n");
            break;
        default:
            printf("周日\n");
            break;
    }
    return 0;
}

修改版

int main()
{
	int day = 6;
	switch (day) {
	case 1:
		printf("周一\n");
		break;
	case 2:
		printf("周二\n");
		break;
	case 3:
		printf("周三\n");
		break;
	case 4:
		printf("周四\n");
		break;
	case 5:
		printf("周五\n");
		break;
	case 6:
		printf("周六\n");
		break;
	case 7:
		printf("周日\n");
		break;
	default:
		printf("输入有误,请重新输入!\n");
		break;
	}
	return 0;
}

总结

1.switch语法结构中,case完成判定功能,break完成分支功能,default处理异常情况

2.当一条case对应多条执行语句时(不能定义变量),可以放在代码块{}里,但最好放在函数里实现

3.当多条case语句对应一条执行语句时,多条case后面不写break

4.default可以出现在switch种任何地方,但推荐放在结尾

5.case后面不能跟const修饰的常变量,建议要有好的case的布局

综合实例

image.png

分析如图 image.png


以上就是本文的全部内容了,感谢观看,你的支持就是对我最大的鼓励~

u=779924663,1900594976&fm=253&fmt=auto&app=120&f=JPEG.webp