一文带你深入浅出C语言控制语句

目录

前言

1.控制语句总览

2.分支语句

2.1if语句

2.2 例题剖析

2.2.1 例题一 

2.2.2 例题二

2.2.3 例题三

2.3 switch语句

2.4 综合实例

3. 循环语句

 3.1 while语句

3.2 break在while循环中的作用

3.3 continue在while循环中的作用

3.4 一点题外话

3.5 for语句

注意事项

3.6 do...while循环

3.7 循环嵌套

3.8 例题剖析

3.9 二分查找

拓展

3.10 goto语句

题外话

敬请期待更好的作品吧~


一文带你深入浅出C语言控制语句_第1张图片前言

        本文主要分享一波个人对C语言控制语句的学习见解与心得,作者水平有限,难免存在纰漏,读者各取所需即可。 

一文带你深入浅出C语言控制语句_第2张图片 给你点赞,加油加油!

C语句可分为以下五类:

1. 表达式语句

2. 函数调用语句

3. 控制语句

4. 复合语句

5. 空语句

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

1.控制语句总览

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

可分成以下三类:

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

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

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

2.分支语句

2.1if语句

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

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

一文带你深入浅出C语言控制语句_第3张图片

2.2 例题剖析

2.2.1 例题一 

        为什么啥也不输出呢?

一文带你深入浅出C语言控制语句_第4张图片

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

一文带你深入浅出C语言控制语句_第5张图片

一文带你深入浅出C语言控制语句_第6张图片

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

一文带你深入浅出C语言控制语句_第7张图片

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

2.2.2 例题二

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

一文带你深入浅出C语言控制语句_第8张图片

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

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

一文带你深入浅出C语言控制语句_第9张图片

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

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

2.2.3 例题三

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

一文带你深入浅出C语言控制语句_第10张图片

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

一文带你深入浅出C语言控制语句_第11张图片

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

一文带你深入浅出C语言控制语句_第12张图片

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

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

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

2.3 switch语句

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

switch(整型表达式)
{  

 语句项;

}

语句项就是一些case语句:

case 整型常量表达式:    

        语句;

比如:

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

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

一文带你深入浅出C语言控制语句_第13张图片

        如果表达的值与所有的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语句,以便在所有条件都不满足的情况下进行响应或说明。

6.如果多个不同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后面要放入多条语句的话最好都封装到函数里面去。

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

        答案是:不行

        比如:

int main()
{
	const int a = 10;
	int b = 10;
	switch (b) {
	case a: //不行
		printf("hello\n");
		break;
	default:
		break;
	}
	return 0;
}

8. 建议按执行频率排列case语句,把最常执行的情况放在前面而把最不常执行的情况放在后面。

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

9. 将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的布局

2.4 综合实例

一文带你深入浅出C语言控制语句_第14张图片

分析如图

一文带你深入浅出C语言控制语句_第15张图片

3. 循环语句

 3.1 while语句

        当满足while()括号里的条件也就是括号内表达式为真时,执行while后面语句,直到表达式值为假为止。

while(exp)
{
    //...可以是各种语句
}

一文带你深入浅出C语言控制语句_第16张图片

3.2 break在while循环中的作用

        其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。

        若是有循环嵌套的话break只能跳出一层循环,若是循环里的if语句里的,一样跳出循环。

        所以:while中的break是用于永久终止循环的。

3.3 continue在while循环中的作用

         continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。

3.4 一点题外话

        遇到这个问题不要慌,因为已经打开了这个可执行程序所以无法再打开,只需要把原先打开的.exe关掉就行。

        好的习惯:声明变量时初始化值。

        

3.5 for语句

         for()语句括号内有三个表达式,分别对应初始化操作,循环判断条件和循环后调整。

for(exp1; exp2; exp3)
{
    //...可以是各种语句

}

一文带你深入浅出C语言控制语句_第17张图片

        可以发现在while循环中依然存在循环的三个必须条件,但是由于风格的问题使得三个部分很可能偏离较远,这样查找修改就不够集中和方便。

        所以,for循环的风格更胜一筹,for循环使用的频率也最高。 

        我们发现在for循环中也可以出现break和continue,break的话和while中的作用差别不大,但是continue就有所不同了。

continue在for循环中

        当i等于5时,会跳转到哪里呢? 

一文带你深入浅出C语言控制语句_第18张图片

        如果跳转到1处或3处的话,i的值都没有更新,也就是跳过了条件更新,最终会导致死循环,是不是这样呢?我们让代码跑起来看看。

一文带你深入浅出C语言控制语句_第19张图片

         很明显,i的值一直在更新,所以continue在for中是跳转到条件更新处而非条件判断处的。

注意事项

1. 不可在for 循环体内修改循环变量,防止 for 循环失去控制。

2. for循环遵循前闭后开区间,比如for(i = 0; i < 10; i++)也就是i的取值区间为[0,10),更为直观,循环次数明确,比如前面的循环一看就知道要循环10次;便于个数计算,比如for(j = 6; j < 10; j++)直接10-6=4就算出了个数。

3. for循环中的初始化部分,判断部分,调整部分是可以省略的,可以省略一个或多个表达式(但是不能省略分号),但是不建议初学时省略,容易导致问题,尤其是判断部分,如果省略的话意味着条件恒成立,会无限循环下去。

4. 第一个表达式不一定是给变量赋初值,也可以使用printf()。在执行循环的其他部分之前,只对第一个表达式求值一次或执行一次。

5. for(int i = 0; ; )在初始化部分创建变量并初始化,C99标准才支持,C++也支持。

6. 可以使用不止一个变量控制循环

  int x, y;
  for (x = 0, y = 0; x<2 && y<5; ++x, y++)
   {
      printf("hehe\n");
   }

7. 嵌套循环时,尽量把长的循环放内层,短的循环放外层,也就是外小内大,有利于减少循环来回跳转的次数,一般效率会高一些。

    

3.6 do...while循环

        循环至少执行一次,使用的场景有限,所以不是经常使用。

一文带你深入浅出C语言控制语句_第20张图片

#include 

int main()
{
     int i = 1;
     do
     {
        if(5 == i)
            continue;
        printf("%d\n", i);
        i++;
     }while(i<10);
     return 0;
}

        break和coutinue在while和do...while中意义一样。

3.7 循环嵌套

        是指在一个循环内包含另外一个或多个循环,在外面的被称为外层循环,在里面的被称为内层循环。

比如:

for(i = 0; i < 4; i++)
{
    for(j = 0; j < 4; j++)
    {
        printf("* ");
    }
    printf("\n");
}

        可以分别用来处理行和列的数据。

        for和while以及do...while可以互相嵌套,任意组合。

        要注意的是,内层循环在每次外层循环迭代时都执行完所有的循环,所以嵌套循环的执行次数是内外层循环次数的乘积。

3.8 例题剖析

        看看这个循环怎么样。 

 一文带你深入浅出C语言控制语句_第21张图片

        死循环了,一旦i等于5了,就无法再对循环变量进行调整。

        上述代码本来的想法应该是:循环10次,每次循环时如果i==5则打印i的结果。

        但if语句中表达式的==写成了赋值,相当于每次循环尽量都是将i的值设置成了5,5为真,因此每次都会打印5。

        i每次修改成5打印后,i的值永远不会等于10,因此造成死循环。

        结果就是死循环地打印5。

3.9 二分查找

        在查找的时候怎样设计代码比较好?

        比如你在和朋友玩猜数字游戏,他心里想一个一定范围内的数字,假设是0~1000以内,在规定时间内,要你猜一猜,你会怎么猜?当然不可能1,2,3…一点一点猜呀,大家估计都是先对半砍一下——500,不对,小了;那就750,不对还是小了;那825,大了;那……一半一半地砍下去能够很快的缩小查找区间,转眼间就接近目标数字了。

        那在我们设计查找方法的代码的时候就有了二分查找的办法。

int main()
{
    int targ = 0;//查找目标
    int arr[10] = {1, 2, 4, 5, 6, 7, 8, 9, 10, 11};
    int num = sizeof(arr) / sizeof(arr[0]);//数组元素个数

    printf("请输入要查找的元素:\n");
    scanf("%d", &targ);
    int left = 0;
    int right = num - 1;
    int mid = 0;

    for (; left <= right;)
    {
         mid = (right - left) / 2 + left;
        if (targ < arr[mid])
        {
            right = mid - 1;
        }
        else if (targ > arr[mid])
        {
            left = mid + 1;
        }
        else
        {
            printf("找到%d了,对应数组下标为:%d\n", targ, mid);
            break;
        }
    }
    if (left > right)
    printf("找不到");
    return 0;
}

           注意mid的取值,如果是(left + right) / 2的话,想想看,left+right有没有越界的可能,当数值非常大的时候可能存在溢出,再除于2的话值就不是我们想要的中间值了。那怎么办?

先看看这样一个问题:

        我有两根木棒,把它们立起来,现在我想要“取长补短”,让两木棍一样长,但我不想用(长+短)/2,想想看,还有什么办法没?

看看这个:

一文带你深入浅出C语言控制语句_第22张图片

        切掉长出来的部分,然后让长出来的部分对半切,再一边一半:

一文带你深入浅出C语言控制语句_第23张图片

        这下就有办法了:(right - left) / 2 + left

拓展

关于左右端向中靠拢问题,循环的判断条件一般都是left<=right。

例题:演示多个字符从两端移动,向中间汇聚

比如:################

          w##############!

          we############e!

          wel##########re!

          ......

          welcome to here!

int main()
{
    char a[] = "welcome to here!";
    char b[] = "****************";

    int left = 0;
    int right = strlen(a) - 1;

    for (;left <= right; left++, right--)
    {
        b[left] = a[left];
        b[right] = a[right];
        printf("%s\n", b);
    }
    return 0;
}

3.10 goto语句

        C语言中提供了可以随意使用的 goto语句和标记跳转的标号。

        从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。

        但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。

例如:一次跳出两层或多层循环。 多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环。

一文带你深入浅出C语言控制语句_第24张图片

        goto只能在同一个函数内跳转,它无法从一个函数跳转到另一个函数去。

题外话

如何用C语言关机?

使用系统命令:shutdown

在cmd窗口输入shutdown -s -t 60即可设置计算机在60s后关机

输入shutdown -a即可取消该命令


敬请期待更好的作品吧~

感谢观看,你的支持就是对我最大的鼓励,阁下何不成人之美,点赞收藏评论走一波~

一文带你深入浅出C语言控制语句_第25张图片

你可能感兴趣的:(一文深入浅出C语言,c语言)