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语言语法有误,不能生成可执行文件。

原文地址:https://www.cnblogs.com/zjlbk/p/11159968.html