C语言(十)

作业分析讲解

=====================

1. 数组直接当成形参--》迷惑有些同学,表面上好像不是指针,很多同学理解为传值

                                      数组作为形参或者作为实参都是传递的地址

    void foo(int b[3][3])

   {

             ++b;  //b跟数组名a等价,是int (*)[3]数组指针

             b[1][1]=9  //等价于  *(*(b+1)+1)      b指向{7,9,9}

    }

    启发:  去面试遇到指针看不懂--》一定想办法换算成你最熟悉

                 遇到二级指针--》换算成一级方便查看

                 遇到二维数组--》换算成数组指针,或者其他类型的指针

 

C语言的函数

=========================

             第五个: 递归函数(递归思想)

                             经验:分析问题的时候,发现问题解决步骤后面的步骤跟前面的步骤有数学上的关系,就可以用递归

                            1+.........+n  //以前是用循环实现

                             特点:自己调用自己,这一类函数就是递归函数

                             缺点:递归函数如果递归的次数太多,有可能导致栈溢出

练习: 使用递归函数,实现求1到n的和

                int  fun(n)     n+fun(n-1)-->n+n-1+fun(n-2)

             第六个:函数调用的过程(理论)

                             计算机的内存分为不同的区域:  栈内存   堆内存

                             堆内存(heap):C语言中malloc  calloc  realloc三个函数申请的内存空间就是堆空间

                                           特点:  申请需要用到三个函数,使用完毕必须使用free释放掉(如果不释放会引起内存泄漏),不会随着你的程序的退出而自动释放

                                          内存泄漏:一直申请堆内存,但是都没有释放,导致堆内存越来越少,最后没有可以使用的堆内存

                              栈内存(stack): 函数调用进栈出栈,局部变量保存在栈空间

                                                        特点:先进后出

                                                                   栈空间是很小,不同的系统有所差别,大致8M左右

                              数据段(.data):细分为3个部分

                                                           .bss段

                                                          .data段

                                                          .rodata段

                              代码段(.text):细分为2个部分

                                                          .text段        专门用来存放C语言程序中的代码语句 printf   strcpy

                                                          .init段         存放的是系统的一段启动代码(帮你找到main函数的入口地址,然后启动执行main函数)

                   总结:  函数调用就是一个不断地进栈(调用的时候),出栈(函数执行完毕)

                                如果代码中要定义比较大的数组,建议你使用堆空间(堆空间比栈空间大很多)

练习:

      #include <stdio.h>  代码段  .text

      int  n;  //未初始化的全局变量--》 .bss

      int  m=99; //初始化的全局变量 --》 .data

      void fun(int n)  --》局部变量   栈

      {

               printf("world"); //代码段  .text

               if(n<10)  //代码段  .text

                     n+=8;  //  栈

               return 0;   //代码段  .text

      }

      int main()

      {

                char  *p=malloc(100); // p是局部变量   100字节堆空间

               char   buf[10]="yueqian";  //局部变量  栈

               fun(88);  //栈     常量88  .rodata

       }

       

 

    

 

             第七个:内联函数(简单的代码,多次使用的,你就定义成内联)

                    作用: 解决函数调用时候入栈出栈的资源消耗

                                如果函数的代码很简单,你需要反复经常使用(建议你定义成内联函数,节约函数调用时候入栈出栈的时间耗费,提高效率)

                    语法:inline  返回值  函数名字(参数)

                               {

 

                              }

                    缺点: 由于内联函数的底层原理:  编译器遇到内联函数,不会让它入栈,编译器会把内联函数的源码直接搬到你的main中,类似于这个代码直接写在了主函数里面(增加了主函数占用的内存),耗费了比较多的内存

                   

             第八个:函数指针和指针函数(跟数组类似的概念)

                            函数指针:  该指针指向一个函数

                                                 类型  * 指针名

                                                 C语言规定:函数名就是这个函数在内存中入口地址(首地址)

                                                                     函数名就是个指针

                                                char  a[4];         char  [4]

                                                int  fun(int  a);  //类型为   int  (int)

                                                 int  (*p)(int)=fun;  

                                                void  fun();   // 类型   void  ()

                                                void  (*p)()=fun;

                              作用:跟其它类型的指针一样,通过函数指针去调用函数

                             指针函数:只要一个函数的返回值类型是个指针,这个函数就是指针函数

                                                char *fun();   //指针函数

                                                char fun(char *buf);  //不是指针函数

                                               注意: 指针函数把指针作为返回值,需要注意千万不要返回局部变量的地址(很危险,局部变量会随着函数调用完毕自动释放地址)

                                                           解决方法:指针函数返回指针--》一定要使用堆空间的指针

             第九个:变参函数(原理)和回调函数(理解概念,实现代码)

                           变参函数:函数的参数个数,类型是不确定的

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

                                 语法格式:任何变参函数,第一个参数必须是明确,后面的参数无所谓了

                                                    变参函数必须要有 ...(三个小数点,不能多不能少)

                          变参函数的原理: 由确定的参数(第一个参数),通过指针(va_list    va_start()从起始位置开始)遍历,推导不确定的参数(后面的变参)

                          回调函数: 我通过调用A函数,A函数又帮我自动去调用B函数,B函数被称为回调函数

                                             关键点:必须要有函数指针作为A的参数,通过这个函数指针指向B

                                       void (*signal(int sig, void (*func)(int)))(int);  //不理会它的原型

练习:

        1.  模仿我刚才写的回调函数,模拟信号灯

                        B函数

                       A函数         void  dirve(红灯,B函数指针)

                                          void  dirve(绿灯,B函数指针)

                                          void  dirve(黄灯,B函数指针)

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值