C语言---分支和循环语句

简介: 本章介绍C语言中的分支语句(if,switch)和循环语句(for,while,do...while)和goto语句。

1、什么是语句

C语言语句可以分为五类:

  • 表达式语句
  • 函数调用语句
  • 控制语句
  • 复合语句
  • 空语句

C语言有九种控制语句

可以分成一下三类:

  • 条件判断语句也叫分支语句:if语句,switch语句;
  • 循环执行语句:do while语句、while语句、for语句;
  • 转向语句:break语句、goto语句、continue语句、return语句。

2、if语句

if语句的语法结构:

if (表达式)             //表达式结果如果为真或者非0,那这个表达式就会运行
    语句;
if (表达式)           
    语句;             //这里如果只有一条语句,那就不需要带{},也可以带
else
    语句2;


if (表达式)           
    语句1;             //这里大于一条语句,那就需要带{}
    语句2;
else
    语句2;
//多分支
if (表达式1)           
    语句;            
else if(表达式2)
    语句2;
else
    语句3;


//注意:如果一个表达式同时满足if语句有满足else if语句,因为if语句先接收的这个表达式,那这个表达式只会进入到if语句里面。

2.1、if是和靠的最近的else相匹配的

下面先来看段代码:

#include <stdio.h>
int main()
{
    int a = 0;
    int b = 2;
    if (a == 1)
        if (b == 2)
            printf("hehe\n");
    else
        printf("haha\n");
    return 0;
}

输出:

image.png

显而易见这里的输出竟然为空!!!

这是问什么呢?不应该是输出:haha 的结果吗?为什么不对呢?

这是因为else是会和最近的if进行匹配,所以输出为空。

image.png

所以说代码的结构应该是这样:

#include <stdio.h>
int main()
{
    int a = 0;
    int b = 2;
    if (a == 1)
        if (b == 2)                        //它们的缩进在一起的!!!
            printf("hehe\n");
        else                               //它们两个是一对
            printf("haha\n");
    return 0;
}

总结:else和if是靠的最近进行匹配的,不是说else和if在同一缩进进行匹配的。

3、switch语句

switch语句也是一种分支语句

常常用于多分支的情况

比如:

输入1,输出星期一
输入2,输出星期二
输入3,输出星期三
输入4,输出星期四
输入5,输出星期五
输入6,输出星期六

语法:

switch (整型表达式)
{
        语句项;
}

而语句项是什么呢?

//语句项是一些case语句
//如下:
case 整形常量表达式      //case后面必须是整形常量,当然使用字母表示也行,因为字母的ASCII也是整数
    语句;

使用switch实现星期查询

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{    
    int day = 0;
    scanf("%d", &day);
    switch (day)
    {
    case 1:
        printf("星期一\n");
        break;
    case 2:
        printf("星期二\n");
        break;
    case 3:
        printf("星期三\n");

    case 4:
        printf("星期四\n");
        break;
    case 5:
        printf("星期五\n");
        break;
    case 6:
        printf("星期六\n");
        break;
    case 7:
        printf("星期日\n");
        break;
    }
    return 0;
}

说下switch原理:

从switch中输入相对应的编号,根据编号找到相对应的case语句,这样就算进入switch语句了,然后匹配后经过break语句出switch语句。

3.1、新的需求

要求:

  • 输入1-5,输出“weekday”
  • 输入6-7,输出“weekend”
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{    
    int day = 0;
    scanf("%d", &day);
    switch (day)
    {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        printf("weekday\n");
        break;
    case 6:
    case 7:
        printf("weekend\n");
        break;
    }
    return 0;
}

这说明case语句在没有遇到break语句之前是一下向下执行,知道遇见break语句才会跳出switch语句。

3.2、default字句

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

其实也没什么,都不匹配最终肯定是会全部跳过而已。

程序也不会终止,也不会报错,但是当在都不匹配的情况下我们最后提示一下。

那这就需要default字句了。

注意:switch语句中只能出现一个default字句

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{    
    int day = 0;
    scanf("%d", &day);
    switch (day)
    {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        printf("weekday\n");
        break;
    case 6:
    case 7:
        printf("weekend\n");
        break;
    default:                         //所示
        printf("输出错误");
        break;
    }
    return 0;
}

输出:

image.png

4、循环语句

  • while
  • for
  • do while

4.1、while

语法结构

while (表达式)
{
    循环语句;
}

4.1.1、break语句

只要while循环中执行了break语句,那么整个while循环将会停止,这个break语句在while循环的那任何部分中,while都会立即终端

代码示例:

#include <stdio.h>
int main()
{
    int a = 1;
    while (a < 11)
    {
        if (5 == a)
        {
            break;      //这个break语句看着是在if语句中。但是一旦它被执行,那么整个while语句将会停止
        }
        printf("%d\n",a);
        a++;
    }
    return 0;
}

输出:

image.png

4.1.2、continue语句

一旦在while语句中执行了continue语句,那么此次循环将会直接跳过continue后面的代码,然后判断循环,如果继续则直接进行下一次循环(就直接从while (a<11)处开始执行)。

#include <stdio.h>
int main()
{
    int a = 1;
    while (a < 11)
    {
        if (5 == a)
        {
            continue;        //当a=5时,不在执行后面的代码,直接跳过从while循环开始
        }
        printf("%d\n",a);
        a++;
    }
    return 0;
}

输出:一直死循环的输出:1 2 3 4

image.png

4.2、使用while循环清理缓冲区

4.2.1、getchar()和putchar()

  • getchar()函数用于从键盘上读取数据和scanf一样
  • putchar()函数用于输出数据
#include <stdio.h>
int main()
{
    int ch = getchar();   //我们在键盘中输入“e”,这个e会被转为相应的ASCII值存入ch中
    printf("%c\n", ch);   //然后在转为字符(%c)进行输出
    putchar(ch);          //这个可以直接输出,和上面的打印的效果是一样的,这是另一种方法
    return 0;
}

输出:

image.png

但是这里我们有个疑问:

int ch = getchar();

明明getchar()接收的是个字符,为什么我们要用int类型来接收呢?为什么不用char类型接收呢?

这里解释一下:
因为在读到字符时,会转为相应的ASCII码值,所以说放在int类型是没有问题的。

重点:如果getchar()在读取过程中遇到了错误/不正常或者遇到了文件结束,那么这个函数会返回个EOF

EOF--------end of file文件结束标志

我们来看一下EOF的定义(define)

#define EOF    (-1)

可以看到EOF定义的值是-1,-1是个整数,所以说我们接收getchar()返回的数据就应该用int类型去接受

那好知道了这些我们就可以用while循环来实现清理缓冲区的功能:

#include <stdio.h>
int main()
{
    int ch = 0;
    while ((ch = getchar()) != EOF)    //这里ch接收getcha返回的数据不等于EOF,说明返回的是个正常的字符,那就可以正常输出
    {
        putchar(ch);
    }
    return 0;
}

输出:

image.png

会发现输出不会停止,这时Ctrl+z,然后在回车就可以终止程序了。

Ctrl+z就是让getchar返回一个EOF,这样程序就终止了

【重点:】下面来好好理解一下这个程序的逻辑:

这里先提出个问题?为什么上面的输出会自动换行?

这里设计到缓冲区的概念

我们所知道的scanfgetchar函数来从键盘上获取数据,是我们从键盘上一输出字符,scanfgetchar函数就能接收到的吗?其实并不是,正确的顺序是:我们在键盘上输出字符,这个字符会进入缓冲区,此时scanfgetchar函数检测到缓冲区有字符,这个时候scanfgetchar函数才会把该字符从缓冲区中拿出来。

那为什么会自动换行呢?

image.png

还是上面代码流程分析:当我们输入“a”并且回车后,(回车相当于输入了\n),首先判断a!=EOF,因此执行putchar(ch)然后打印出“a”,然后再次循环,因为缓冲区里里面“a”已经被读取了,所以还剩个“\n”,然后getchar直接读取,因为“\n”!=EOF,所以在次执行putchar(ch),所以就会自动换行了。

4.2.2、深度解析---清理缓冲区这段代码

先来看段代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    char password[20] = { 0 };
    printf("请输入密码:>");
    scanf("%s", password);   //这里不用在&password,因为数组名就是数组首元素地址,所以不用取地址
    printf("请确认密码(Y/N):>");
    int ret = getchar();
    if (ret == 'Y')
        printf("Yes\n");
    else
    {
        printf("No\n");
    }
    return 0;
}

输出:

image.png

显然这样的输出结果是不对的,明明我还没确认,程序直接就打印了NO

分析:当我们在键盘中输入:abcdef,然后回车(\n),此时输入缓冲区里面有了:“abcdef\n”,scanf指挥取它所需要的。因此scanf把“abcdef”给拿走了,因此password=“abcdef”,但是此时缓冲区里面还有个“\n”,然后程序向下走getchar获取数据,一看缓冲区里面还有个“\n”,因此getchar直接拿走了“\n”,然后进入if判断,“\n”!='Y',所以程序输出No。

image.png

那怎么解决呢?我们想办法只要让缓冲区里面没有字符就行了,可以这样实现:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    char password[20] = { 0 };
    printf("请输入密码:>");
    scanf("%s", password);   
    getchar();     //这里在添加个getchar(),提前把那个\n读取掉,那下面那个getchar()就可以正确判断了
    printf("请确认密码(Y/N):>");
    int ret = getchar();
    if (ret == 'Y')
        printf("Yes\n");
    else
    {
        printf("No\n");
    }
    return 0;
}

但是这种写法是比较粗鲁的,不适用每一种情况。比如:我们在键盘中输入:abcdef sdf(中间有个空格)

image.png

这样又不行了。我们来分析一下为什么又出错了:

首先scanf会读取缓冲区里面的“abcdef”,也就是说scanf会读取到空格前,紧接着第一个getchar()会读取空格,那就相当于第一个getchar()被使用了,然后下面的getchar()会读取到sdf,因为'sdf' != 'y',所以会输出No。

这是我们能感知到,第一个错误的解决办法是需要清理缓冲区里面的一个字符,而这个是需要清理缓冲区里面的许多个字符才能解决,因此我们需要循环解决。

我们可以循环使用getchar()把空格到“sdf”以及后面的“\n”全部读取掉,这样就行了

下面我们来实现个正确的方法:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    char password[20] = { 0 };
    printf("请输入密码:>");
    scanf("%s", password);   
    int ch = 0;                          //start
    while ((ch = getchar()) != '\n')
    {
        ;
    }                                    //end
    printf("请确认密码(Y/N):>");
    int ret = getchar();
    if (ret == 'Y')
        printf("Yes\n");
    else
    {
        printf("No\n");
    }
    return 0;
}

5、for循环

5.1、语法

for (表达式1;表达式2;表达式3)
    {
        循环语句;
    }

表达式一:表达式一为初始化部分,用于初始化循环变量的。

表达式二:表达式二为条件判断部分,用于判断循环时终止。

表达式三:表达式三为调整部分,用于循环条件的调整。

for循环执行顺序:

第一遍循环:

image.png

第2、3、4、5、6...循环:

image.png

5.2、break,continue

在for循环和while循环里面break语句的效果一样。

同样在for循环和while循环里面continue语句有一点小差别

如下图:

image.png

其中for循环在遇见continue语句后是跳过后面的代码,然后跳到“i++”(调整)中去了

二while循环在遇见continue语句后是跳到了判断里面去了。

5.3、for语句的循环控制变量

建议:

  • 不可在for循环体内修改循环变量,防止for循环失去控制。
  • 建议for语句的循环控制变量取值采用“前闭后开区间”写法。

5.4、for循环的变种

1、死循环

#include <stdio.h>
int main()
{
   
   
    for (;;)
    {
   
   
        printf("hehe\n");
    }
    return 0;
}

结论:for循环的判断部分省略意味着判断或恒成立,而初始化,调整省略没事(但最好不要省略)。

2、for循环采用多个变量去控制

#include <stdio.h>
int main()
{
    int x, y;
    for (x = 0, y = 0; x < 2 && y>5; ++x, y++)
    {
        printf("hehe\n");
    }
    return 0;
}

6、do-while循环

6.1、do语法

do
    {
    循环语句;
    }    
while(表达式);

打印1-10:

#include <stdio.h>
int main()
{
    int i = 1;
    do
    {
        printf("%d ", i);
        i++;
    } while (i <= 10);
    return 0; 
}

do循环最少循环一次。

6.2、break和continue

作用一样。

7、goto语句

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

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

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

例如:一次跳出两层或多层循环。

多层循环这种情况使用break是达不到目的的,它只能从内层循环到上一层的循环。

先来看一下goto的效果:

#include <stdio.h>
int main()
{
again:                     //标签
    printf("hehe\n");
    printf("haha\n");
    goto again;
    return 0;
}


//但是goto不能跨函数跳转,如下就是不行的
void test()
{
    again;
}

int main()
{
    printf("hehe\n");
    printf("haha\n");
    goto again;
    return 0;
}

image.png

goto语句真正适合的场景下:

for (...)
    {
        for (...)
        {
            for (...)
            {
                if (disaster)
                    goto error;            #这样可以根据error标签直接跳过两层for循环
            }
        }
    error:
        if (disaster)
            //处理错误情况
    }

7.1、使用goto语句模拟关机程序

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#include <string.h>
int main()
{
    char input[20] = { 0 };
    system("shutdown -s -t 60");             //电脑在60s内关机
again:
    printf("电脑即将在60秒内关机,如果不想关机,输入:我是猪,即可解决。\n");
    scanf("%s", input);
    if (strcmp(input, "我是猪") == 0)
    {
        system("shutdown -a");
        printf("已取消关机\n");
    }
    else
    {
        goto again;
    }
    return 0;
}

输出效果:

image.png

当然我们也可以使用循环的方式替代goto

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#include <string.h>
int main()
{
    char input[20] = { 0 };
    system("shutdown -s -t 60");             //电脑在60s内关机
    while (1)
    {
        printf("电脑即将在60秒内关机,如果不想关机,输入:我是猪,即可解决。\n");
        scanf("%s", input);
        if (strcmp(input, "我是猪") == 0)
        {
            system("shutdown -a");
            printf("已取消关机\n");
            break;
        }
    }
    return 0;
}
相关文章
|
2月前
|
C语言
初识C语言2——分支语句和循环语句
初识C语言2——分支语句和循环语句
71 5
|
2月前
|
C语言
【c语言】分支语句
C语言通过三种基本结构——顺序、选择和循环,构建复杂的程序逻辑。本文主要介绍了C语言的选择结构,即if-else语句及其变体,包括简单的if语句、if-else组合、else if多分支判断、嵌套if以及解决悬空else问题的方法。此外,还详细讲解了逻辑运算符和关系运算符的使用,以及如何利用条件操作符简化逻辑判断。最后,文章对比了if-else与switch语句在实现多分支逻辑时的应用,并解释了switch语句中的break和default关键字的作用。
31 8
|
2月前
|
C语言
【c语言】循环语句
循环结构是C语言中用于简化重复操作的重要工具,主要包括while循环、do-while循环和for循环。while循环是最基本的形式,通过不断检查条件来决定是否继续执行循环体。do-while循环则先执行循环体,再检查条件,至少执行一次。for循环逻辑更复杂,但使用频率最高,适合初始化、条件判断和更新变量的集中管理。此外,循环中还可以使用break和continue语句来控制循环的提前终止或跳过当前迭代。最后,循环可以嵌套使用,解决更复杂的问题,如查找特定范围内的素数。
43 6
|
2月前
|
Serverless C语言
C语言控制语句:分支、循环和转向
C语言控制语句:分支、循环和转向
|
2月前
|
算法 编译器 C语言
【C语言】实现猜数字游戏(分支语句与循环语句的运用)
【C语言】实现猜数字游戏(分支语句与循环语句的运用)
|
2月前
|
C语言
教你快速理解学习C语言的循环与分支
教你快速理解学习C语言的循环与分支
17 0
|
2月前
|
小程序 C语言
初识C语言:走近循环
初识C语言:走近循环
|
2月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
36 3
|
IDE 定位技术 开发工具
C语言 第四章 关系、逻辑运算与分支流程控制
一、关系运算 若干表达式用关系运算符连接而成,就构成关系表达式。 关系表达式中,表达式成立,其值为1(真);表达式不成立,其值为0(假)。其他表达式中,其结果如果是非0则为真,结果为0则为假。 关系运算符的优先级低于算术运算符,高于赋值运算符。
1043 0
|
17天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
31 6