第三篇,嵌入式中控制流语句(接上一篇)和函数详细说明。

一、控制流。  --  switch语句
1、为什么会有switch语句?
就是因为if/else语句,如果出现分支多的情况,那么就会造成代码很累赘。

2、基本框架?
aaaa;
switch(判断的值)    --> 整型、字符型、枚举类型   --> 不可以填字符串、浮点型、数组、指针。
{
    case 结果1:    //如果判断的值等于结果1,则执行bbbb。
        bbbb;
        break;  //break在switch语句中作用:结束分支。

    case 结果2:    //如果判断的值等于结果2,则执行cccc。
        cccc;
        break;  //break在switch语句中作用:结束分支。

    default:        //如果判断的值不满足以上的所有结果,则会执行dddd。
        dddd;
        break;
}
eeee;

3、处理流程。
aaaa;    -->  判断的值是否与下面的case语句后面的结果一致,例如判断的值等于结果2  --> 执行cccc  --> eeee

   例题:  从键盘中获取一个值,存放在变量中。
           数字1   --> 打印one
           数字10  --> 打印ten
       如果都不是  -> 打印error

#include <stdio.h>

int main(int argc,char *argv[])
{
    int x;
    scanf("%d",&x);
    
    switch(x)
    {
        case 1:
            printf("one!\n");
            break;
        case 10:
            printf("ten!\n");
            break;
        default:
            printf("error!\n");
            break;
    }
    
    return 0;
}

4、如果不写break语句会怎么样?   --> 会一直往下运行代码
int main()
{
    int c = 1;
    switch(c)
    {
        case 1:
            c++;
        case 2:
            c+=5;
            break;
        default:
            c+=4;
    }
    printf("c = %d\n",c);  //7
}

5、switch语句能不能进行范围判断?

   从键盘中获取一个数字
   0~100    --> small
   100~200  --> middle
   201~300  --> large
   其他     --> error

#include <stdio.h>

/*
0~100    --> small
101~200  --> middle
201~300  --> large
其他     --> error
*/

int main(int argc,char *argv[])
{
    int x;
    scanf("%d",&x);
    
    switch(x)
    {
        case 0 ... 100:
            printf("small!\n");
            break;
            
        case 101 ... 200:
            printf("middle!\n");
            break;
            
        case 201 ... 300:
            printf("large!\n");
            break;
            
        default:
            printf("error!\n");
            break;
    }
    
    return 0;
}

6、switch语句容易错的地方。
1)判断的值必须是整型。
2)每一个case语句后面记得添加break;  除非有意去执行后面的代码
3)记得写default,即使这个default永远都不会执行。
4)break语句在switch语句是跳出switch分支,与循环无关。
5)在进行范围判断时,记得"..."的两边一定有空格,不然也是编译出错。

二、两个影响着控制流的语句。  --  break语句和continue语句。
1、break语句。
1)作用对象:switch语句、       for循环、while循环、do_while循环。
2)作用:    跳出switch语句     跳出循环

2、作用场景:
1)当break作用于switch语句的时候:
switch(x)
{
    case 1:
        xxx;
        break;   --> 仅仅是跳出switch语句而已。
}
yyy;

2)当break语句作用于循环时,一般都是与if分支连用。
aaa;
while(1)
{
    xxx;
    yyy;
    if(判定条件)   //如果判定条件为真,那么就执行break语句
    {
        break;  //跳出循环(虽然与if语句连用,但是break跳出不是if,而是循环)
    }
}
bbb;

处理流程:
aaa --> xxx;  --> yyy;  --> 判定条件  -> 真  --> break  --> bbb;

3、几个特殊的例子。
1)

int main()
{
    while(1)
    {
        while(1)
        {
            while(1)
            {
                break;
                xxx;
            }
            yyy;   --> 当break语句执行后,就会运行yyy
        }    
        zzz;
    }
    qqq;
    return 0;
}

2)
int main()
{
    while(1)
    {
        switch(x)
        {
            case 1:
                break;
        }
        xxx;  --> 当break语句执行后,就会执行xxx
    }
    yyy;
}

 
练习:
int main()
{
    int k=5,n=0;
    do{
        switch(k)
        {
            case 1:
            case 3: n+=1;  break;    
            default: n=0; k--;
            case 2:
            case 4: n+=2; k--;  break;
        }
        printf("%d\n",n);
    }while(k>0 && n<5);           // 2345    
}

2、continue语句。
1)作用对象: for循环、while循环、do_while循环。
2)作用:     立即结束当次循环,马上开始下一次循环。

3)场景:
aaa;
while(1)
{
    xxx;
    if(判定条件)
    {
        continue;
    }
    yyy;
}
zzz;

处理流程:
aaa;  -->  xxx;  -> 判定条件  --> 真  -->  continue  --> xxx;  -> 判定条件  -> 假  -> yyyy  --> xxx;


三、函数概念。
1、什么是函数?
C语言是一种面向过程的语言,任何的一个大过程都可以拆分为多个小过程。
大过程  --> 程序
小过程  --> 函数

C语言称之为函数式语言  -> C语言程序是由函数堆砌出来的。
函数其实就是一个模块的封装。  --> 例如: 快餐店就是(买菜,做菜,端菜,洗碗)的一个封装。

2、封装成函数有什么意义?
1)简化代码,使得代码变成一个独立的模块

int main()
{
    int a = 吃早餐();   //a就是存储着吃早餐这个过程的结果
    if(a == 0)
    {
        printf("我吃饱了");
    }
    else{
        printf("我没吃饱");
    }

    搭地铁();
    上课();
    吃饭();
}

2)方便工程师后期维护项目。
3)对于调用者而言,不需要关心实现过程,只需要关心调用函数之后的结果就可以。

四、函数书写规则。
1、在C语言中,有哪些函数种类?
main函数:主函数,在程序中有且仅有一个,程序从main函数开始,从main函数结束。
系统函数:在man手册的第2手册,用户只需要调用即可,不需要写实现过程。
库函数:  在man手册的第3手册,用户只需要调用即可,不需要写实现过程。
自定义函数:不能通过man手册去查询,用户必须要写清楚函数实现过程才可以调用。
   

#include <stdio.h>
int main(int argc,char *argv[])
{
    printf("helloworld!\n");  //调用库函数,用户不需要写实现过程
    
    //my_fun(); //调用自定义函数,用户必须要写清楚函数实现过程,才可以调用
    
    return 0;
}

2、如何书写自定义函数?
1)确定函数的函数名。
必须:   命名规则与变量声明规则一致。  例如:my_fun
非必须: 函数名最好能够体现函数的功能。例如:play_music

2)确定函数的形式参数。  --> 写在函数名的后面。
有形式参数: my_fun(形式参数1,形式参数2,形式参数3,...);
无形式参数: my_fun()

吃早餐(一些钱,哪种面包)  --> 你想调用吃早餐这个函数,就必须向函数中传递金钱金额以及面包的种类。
快餐店(一些钱,哪些菜,用餐人数)
my_fun(int a)            --> 你想调用my_fun这个函数,就必须向函数中传递一个整型数据。
my_fun()                 --> 你想调用my_fun这个函数,直接调用就可以了,不需要传递任何额外的参数。

3)函数体。
my_fun(int a)  -->函数头
{              -->函数体
     /* 函数的实现过程 */

}

4)确定返回值类型   --> 写在函数名的前面
有返回值   --> 必须确定好类型
       int  --> 无论这个函数成功还是失败,都会返回一个int类型的数据。    
       char --> 无论这个函数成功还是失败,都会返回一个char类型的数据。

int my_fun(int a)
{


    return 0;  //0就是返回值的结果,必须与这个int匹配。
}

无返回值  ---> void  代表这个函数没有返回值
void my_fun(int a)
{

    return;  --> 代表该函数返回,但是没有返回值结果。
}

总结自定义函数框架:
返回值类型 函数名字(形式参数列表)
{
    ....;
    ....;
    return ?;
}

   例题: 写一个函数,要求接收两个int类型的数据,函数功能是求和。

#include <stdio.h>

int add_sum(int x,int y)
{
    int z;
    z = x + y;
    return z;
}

int main(int argc,char *argv[])
{
    int ret = add_sum(10,20);
    printf("ret = %d\n",ret);  //30
    return 0;
}

五、如何调用函数?
1、确保调用的函数的实现过程已经写好了。
int add_sum(int x,int y)  //x,y形式参数    x=10  y=20
{
    int z;
    z = x + y;
    return z;
}

2、在函数体内,直接写函数的名字就可以了,后面紧跟着一个圆括号,圆括号写实际参数。
int main()
{
    add_sum(10,20);   //10,20  --> 实际参数
              //当我们调用该函数时,会直接将10赋值给x,将20赋值给y    
}

   结论: 形式参数的值是由实际参数直接初始化,这个过程是不可逆的。

思考题:不可逆是什么意思?
修改b的值,a的值不会受到影响。

func(int b)  //b = a
{
    b = 200;
}

int main()
{
    int a = 100;
    func(a);  //a是实际参数
    printf("a = %d\n",a);  //100
}

3、往往调用函数时,都要保存函数的返回值结果,那么这样就知道函数的结果是什么。

关心返回值是什么:
int ret;
ret = add_sum(10,20);
printf("ret = %d\n",ret);

不关心返回值是什么:
add_sum(10,20);


   练习1: 写一个函数,实现接收3个int类型的数据,要求函数内经过约定的计算之后,得到结果并打印出来。
       前面2个参数用于计算,最后一个参数是计算方式。
    
       1 -> +
       2 -> -
           3 -> *
       4 -> /

func(3,4,1);  -> 7
func(3,3,4);  -> 1

#include <stdio.h>

int my_func(int x,int y,int z)
{
    int ret;
    switch(z)
    {
        case 1:
            ret = x + y;
            break;
            
        case 2:
            ret = x - y;
            break;
            
        case 3:
            ret = x * y;
            break;
            
        case 4:
            ret = x / y;
            break;
    }
    return ret;
}


int main(int argc,char *argv[])
{
    int ret = my_func(3,4,4);
    printf("ret = %d\n",ret);
    
    return 0;
}

六、函数声明。
1、函数的定义与函数的声明有什么区别?

函数的定义:它包含了函数的名字、函数形参、函数返回值类型、函数的实现过程。
int add_sum(int x,int y)  
{
    int z;
    z = x + y;
    return z;
}

函数的声明:它包含了函数的名字、函数形参、函数返回值类型。
int add_sum(int x,int y);

2、什么时候需要写函数的声明?
1)如果函数的定义写在main函数的前面,则不需要声明该函数。

#include <stdio.h>

int add_sum(int x,int y)
{
    int z;
    z = x + y;
    return z;
}

int main(int argc,char *argv[])
{
    int ret = add_sum(10,20);
    printf("ret = %d\n",ret);  //30
    return 0;
}

2)如果函数的定义写在main函数的后面,则需要声明该函数。

#include <stdio.h>
int add_sum(int x,int y);  //如果不声明,就会编译警告。

int main(int argc,char *argv[])
{
    int ret = add_sum(10,20);
    printf("ret = %d\n",ret);  //30
    return 0;
}

int add_sum(int x,int y)
{
    int z;
    z = x + y;
    return z;
}

七、从内存角度去分析函数的调用过程。

请求出以下程序的结果:
int my_fun(int z)
{
    z = z/5;
    return z;  //3
}

int func(int x,int y)
{
    int c;
    c = x + y;
    my_fun(c);   --> 不关心返回值
    return c;  //15
}

int main(int argc,char *argv[])
{
    int a = 10,b = 5;
    int ret = func(a,b);
    printf("ret = %d\n",ret);  //15
    return 0;
}    

1、遇到这种给程序,求结果的题目,直接画内存图来分析。
2、从main函数开始分析。
3、局部变量是在栈区申请空间,全局变量在data/bss段申请空间。
4、当调用函数时,就开始去这个函数中分析代码。
5、形式参数也是属于这个函数中的局部变量。
6、形式参数与实际参数占用不同的内存空间。
7、形式参数的值是由实际参数直接初始化。
8、在函数体内,是执行完return语句之后,局部变量才会释放。
9、函数的返回值会返回到函数调用的地方。

练习2:求出以下结果
int swap(int x,int y)
{
    int t;
    t = x;
    x = y;
    y = t;
    return 0;
}

int main()
{
    int a,b;
    scanf("%d %d",&a,&b);  5 3

    swap(a,b);
    printf("a = %d,b = %d\n",a,b); 5 3
    return 0;
}

为什么没有调换过来?
形式参数的值是由实际参数直接初始化,这个过程不可逆。形式参数x与y的值确实可以交换,但是并没有影响到实参a与b,所以没有调换。

练习3:求出以下结果
int fun(int a,int b)
{
    if(a > b)
    {
        return a;
    }
    else{
        return b;
    }
}

int main()
{
    int x = 3,y = 8,z = 6,r;
    r = fun(2*z,fun(x,y));
    printf("r = %d\n",r);
}

练习4:求出以下程序的结果。
#include <stdio.h>

int get_2_max(int x,int y)
{
    if(x > y)
        return x;
    else
        return y;    
}

int get_4_max(int x,int y,int z,int k)
{
    int m = get_2_max(x,y);  
    m = get_2_max(m,z);      
    m = get_2_max(m,k);      
    return m;    
}

int main(int argc,char *argv[])
{
    //1. 连续从键盘中获取四个数字
    int a,b,c,d;
    scanf("%d %d %d %d",&a,&b,&c,&d);  //10 40 30 20
    
    //2. 求出四个数字的最大值
    int ret = get_4_max(a,b,c,d);
    printf("ret = %d\n",ret);  
    
    return 0;
}


 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肖爱Kun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值