• 2019年7月9日星期二(C语言)


    一、函数嵌套?

    1、 什么是函数嵌套?

    函数嵌套就是调用某个函数内部再调用另外一个函数。

     

    2、 有函数嵌套程序在内存有什么特点?

    如果嵌套的函数很多,就会在栈区累积非常多空间没有被释放。

    3、 函数嵌套与递归函数有什么区别?

    函数嵌套:自己调用别人的函数。

    例子:

    void fun()

    {

           my_fun();

    }

     

    递归函数:自己调用自己的函数。

    例子:

    void fun()

    {

           fun();

    }

    二、递归函数?

    1、 特点?

    递归函数特点自身调用自身,无限递归,没有终止的时刻。

    例子:

    void fun()

    {

           int a;

           fun();  -> 无限递归,没有终止条件  -> 导致栈空间溢出!

           return;

    }

     

    int main()

    {

           fun();

           return 0;

    }

     

    结论: 为了防止栈空间溢出,所以递归函数一般都会携带终止条件,也就是说到达某个条件时,函数返回!

    2、题型1: 给程序,求结果。 

    例题,求出下面程序的结果?

    void fun(int n)

    {

           if(n > 1) 

           {

                  fun(n-1);

           }

           printf("n = %d ",n);

           return;

    }

     

    int main()

    {

           fun(100);

           return 0;

    }

     

    答案:1~100

    思路: 找出终止条件,列出几项,找规律,再画图分析!

     

    3、 题型2: 给规则,写程序。

    例题:写出下列程序。

    5个学生坐在一起,问第5个学生多少岁,他说比第4个学生大2岁。问第4个学生多少岁,他说比第3个学生大2岁。问第3个学生多少岁,他说比第2个学生大2岁。问第2个学生多少岁,他说比第1个学生大2岁。最后问第1个学生多少岁,他说他是10岁,请问第5个同学多少岁?使用递归函数来完成。

    #include <stdio.h>

    int get_child_age(int n)

    {

           int age;

           if(n <= 0)  //  -> 搞事情

                  return -1;

          

           if(n == 1)  //  -> 终止条件

                  age = 10;

                 

           if(n > 1)   //  -> 正常

                  age = get_child_age(n-1) + 2;

          

           return age;

    }

     

    int main(int argc,char *argv[])

    {

           int ret;

           ret = get_child_age(5);

           printf("ret = %d ",ret);

           return 0;

    }

     

    思路: 写框架,分析情况 -> 最终目标与终止条件之间的关系。

      练习1: 画出以上例子的内存图。

      练习2: 有以下程序,求出结果?

    int fun(int n)  10   9

    {

           if(n==1)  return 1;

           else return (n+fun(n-1));  10+9+8+7+6+5+4+3+2+1

    }

     

    int main()

    {

           int x;

           scanf("%d",&x);  //若输入一个数字10。

           x = fun(x); 10

           printf("%d ",x);  //55

    }

     

      练习3:第1天存100块,后面每一天都比昨天多存10块,第312天存了多少?

    #include <stdio.h> 

    int get_money(int n)

    {

           int money;

           if(n <= 0)

                  return -1;

           if(n == 1)

                  money = 100;

           if(n > 1)

                  money = 10 + get_money(n-1);

          

           return money;

    }

     

    int main()

    {

           int ret;

           ret = get_money(10);

           printf("ret = %d ",ret);

           return 0;

    }

     

       练习4: 使用循环方式完成练习3,画内存图分析两种方式差别。

     

    循环  -> 多次使用一个变量

    递归  -> 每次都开辟一个新的变量空间   --> 容易造成栈空间溢出!

    三、回调函数

    1、 什么是回调函数?

    先定义好函数A(喝水),再将这个函数A作为另外一个函数B(爬山)的参数,在函数B(爬山)可以回过头调用这个参数(喝水),这个函数A就称之为回调函数。

    2、 基本框架?

    void funB(funA)

    {

           funA.....  在函数B中调用函数A

    }

     

    void funA()  -> 回调函数

    {

     

    }

     

    int main()

    {

           funB(funA);

    }

       例题: 从键盘中获取两个数值,求出两个值的和,要求使用回调函数完成。

    int get_result(int a,int b,int(*p)(int,int))  -> 就把这个p当成函数名字 

    {

           int ret;

           ret = p(a,b);

           return ret;

    }

     

    int add_fun(int x,int y)

    {

           int z;

           z = x + y;

          return z;

    }

    int main()

    {

           int a,b,ret;

           scanf("%d %d",&a,&b);

     

           ret = get_result(a,b,add_fun);  -> 函数名字作为参数,其实是传递了函数的地址过来。

           printf("ret = %d ",ret);

    }

    补充:

    函数指针参数怎么写?

    1)先写一个 *

    2)在*后面写一个变量名,使用圆括号括住  (*p)

    3)确定函数是哪个? int add_fun(int x,int y)

    4)把第3步函数名与形参的变量名都去掉  int  (int,int) 

    5)把第2步结果写在第4步结果的返回值类型与形式参数列表之间    int(*p)(int,int

    3、 回调函数使用场景?

    在数据库、系统编程信号通信中常常看到回调函数。

       练习4: 连续从键盘中获取4个数字,求出其中的最大值,要求回调函数来完成。

    int max4(int a,int b,int c,int d,int(*p)(int,int))

    {

           int m;

           m = p(a,b);

           m = p(m,c);

           m = p(m,d);

           return m;

    }

     

    int max2(int x,int y)

    {

           int z;

           z = (x > y ? x : y);

           return z;

    }

     

    int main()

    {

           int a,b,c,d,ret;

           ret = max4(a,b,c,d,max2);

           return 0;

    }

    四、变参函数

    1、 什么是变参函数?

    变参函数是指该函数的参数不固定,例如:printf()函数。

     

      printf("helloworld! ");  -> 参数为1

      printf("a = %d ",a);     -> 参数为2

      printf("(%d %d) ",x,y);  -> 参数为3

     结论: printf()参数为"1+x"

    2、如何判断一个函数是不是变参函数?

      #include <stdio.h>

      int printf(const char *format, ...);

     

       const char *format: 输出字符串格式

       ... :  参数不定

     

    3、 类似的变参函数有很多: printf() scanf()  ioctl()  fcntl()

    五、内联函数?

    1、 什么是内联函数?

    在程序中调用函数时,需要花费一定的时间进行保护现场与恢复现场,但是使用了内联函数,就既可以使用函数,又不需要花费时间来进行保护现场与恢复现场。

    封装:test.c

    #include <stdio.h>

    void fun()

    {

           printf("hello! ");

    }

    int main()

    {

           fun();

           fun();

           fun();

           return 0;

    }

     

    不封装:test.c

    #include <stdio.h>

    int main()

    {

           printf("hello! ");

           printf("hello! ");

           printf("hello! ");

           return 0;

    } 

    2、 如何实现内联函数?

    test.c

    int main()

    {

           fun();

           fun();

           fun();

           return 0;

    } 

    head.h

    #include <stdio.h>

    inline void fun()

    {

           printf("hello! ");

    }

    3、如何解决保护恢复现场问题?

    1)使用内联函数  -> inline

    2)不要过多封装成函数,当某些表达式组成一个功能时,才封装为一个函数。

     

    4、在嵌入式中哪里看到内联函数?

    在内核链表时看到内联函数。

    六、数组的概念?

    1、 什么是数组?数组与普通变量有什么关系?

    数组其实是集合来的,它是由多个相同类型的普通变量组合而成。当用户需要同时定义多个相同变量时,就可以使用数组。

    2、 定义数组时,需要交代什么东西?

    1)数组元素的个数?

    2)数组中每一个元素的数据类型? -> char short int long float double

     

    定义公式:

    数据类型 数组名字[元素的个数]

    例子:定义一个具有100个int类型变量的数组

          int A[100];

    3、从内存空间分析数组特点:

    int main()

    {

           int a; //在内存空间中连续申请4个字节,使用变量a间接访问这片空间。

           int A[100];  //在内存空间中连续申请400个字节,使用变量A间接访问这片空间。

           printf("sizeof(a) = %d ",sizeof(a));//4

           printf("sizeof(a) = %d ",sizeof(A));//400

           return 0;

    }

    4、定义了数组,编译器如何处理数组?

    例如: int A[100]

    其实分开两个部分进行处理, “int”为第二部分, "A[100]"作为第一部分。

    第一部分  -> 决定内存空间中元素的个数。

    第二部分  -> 决定每一个元素的数据类型

    七、数组的赋值

    1、 定义同时初始化

        数据类型 数组名字[元素的个数] = {初始化列表,每一个成员的值需要使用","分开}。

     

        int A[3] = {100,200,300}; //编译通过

        int A[3] = {100,200};     //编译通过

    #include <stdio.h>

    int main()

    {

           int A[3] = {100,200};

           printf("A[0] = %d ",A[0]); //100

           printf("A[1] = %d ",A[1]); //200

           printf("A[2] = %d ",A[2]); //0

           return 0;

    }

       结论: 当初始化列表元素个数小于数组元素的个数时,没有赋值的元素都会赋值为0。

     

        int A[3] = {100,200,300,400};  //编译警告 

     

       warning: excess elements in array initializer

       warning: (near initialization for ‘A’)

     

    编译警告warning: 在内存空间中,可能有问题,但是还是可以生成可执行文件。

    编译出错error: C语言语法有误,不能生成可执行文件。

  • 相关阅读:
    必须使用"角色管理工具"安装或配置microsoft.net framework 3.5
    RAC和ASM环境下修改控制文件control file
    Spring Boot热部署(springloader)
    Spring Boot返回json数据及完美使用FastJson解析Json数据
    Windwos配置Maven环境变量
    Spring Boot之HelloWorld
    查询SQLSERVER执行过的SQL记录
    《老妈语录》 读后感
    MySql安装
    MyEclipse中常用的快捷键大全
  • 原文地址:https://www.cnblogs.com/zjlbk/p/11159968.html
Copyright © 2020-2023  润新知