c语言之野指针与数组


野指针:随机指向内存的一快内存,会导致内存泄漏。

 

                指向一块不可访问的内存

内存泄漏原因:

                指向一块已经释放的内存。


 如何避免野指针?

   1):当定义一个指针时,该指针没有指向,定义为空,也就是初始化,即

        Int  *p;      ×             / *没有初始化*/

        Int  *p = NULL;     √       /*指针的初始化*/

为什么NULL这么特殊呢,这是因为NULL是系统默认的宏定义,我们可以直接使用,

 系统中是这样定义的:  

  #define  NULL   (void *)0


2):当要往指针指向的空间赋值时,我们应先分配内存空间(malloc函数),分配时要

       检验是否分配成功,成功时,我们就可以使用指针了,当指针使用完成时,注意,

       别忘了要对申请的内存空间释放了,用free()函数。(毕竟用完了别人的东西我们还

       得还给别人,呵呵),这样我们的指针又没有指定的内存给它访问了,因此,还得再

        一次初始化。

       * 注意指针必须为相同类型的指针才可赋值,否者会造成内存越界或取少(也就是

           说步长要相同)


      看下面的这个例子。(只有框架)

      #define   MAX_SIZE   sizeof(char *)  100

      Char *ptr  = (char *)malloc(MAX_SIZE * sizeof(char));   //动态的分配内存

      

      If(NULL ==  ptr)    //检查分配的空间是否分配成功

      {

          Printf(“malloc  error!\n”);    //空间分配不成功

          Exit(1);

      }

      //memset(ptr, ‘\0’ ,  sizeof(ptr) );     //清理分配的内存中的残留垃圾

       Memset(ptr ,  0 ,  MAX_SIZE);    //上一条的优化,提高代码的拓展性

      //bzero(ptr,  MAX_SIZE);        //只能初始化为0  功能没有memset强大

     

     Free(ptr);               //使用后释放内存

     Ptr = NULL;             //避免又成野指针

 

3):  void * ptr : 俗称为万能指针,但只能保存地址,不能操作地址。

 

总的来说:只要养成良好的编程习惯,就能尽量的避免野指针的存在。

 

 

数组

一维数组:

  定义一个整型的一维数组:(输入、输出)

   int a[3];

   int *p = a;

   int  i;

   for(i = 0; i < 3; i++)

     {

   scanf(“ %s”, &a[i]);   //此外还有a+i. p+i. &p[i]

     printf(“ %d\n”,a[i]);   //*(p+i). p[i]. *p(++)

  }




&a:对一维数组的数组名取地址等于数组的地址。

 

*(&a):对一维数组的地址取值等于数组首元素的地址

 

二维数组:

&a:对一维数组的数组名取地址等于数组的地址。

 

*(&a):对一维数组的地址取值等于数组首元素的地址

 

二维数组:

 int a[2][2];          //可以省略行号,不可省略列号。

 int i;

 int j;

 for(i = 0; i < 2; i++)

 {

    for(j = 0; j < 2; j++)

    {

       scanf(“%d”, &a[i][j]);

       printf(“a[%d][%d] = %d\n”,i, j, a[i][j]);

       //scanf(“%d”,*(a+i) + j));

       //printf(“a[%d][%d] = %d\n”,i, j, *(*(a + i) + j));

    }

 }

对于:*( * ( a + i ) + j)  拆开来找规律

 a + i ; 第i + 1个一维数组的地址。

 *(a + i): i + 1个一维数组的首元素的地址。

 *(a + i) + j: i + 1个一维数组的第j + 1个元素的地址。

 *(*(a + i) + j): i + 1个一维数组的第j + 1个元素的值。

 *(&a) = a; 对二维数组的地址取值等于首个一维数组的地址。

三维数组:(同理)

*(*(*(a + i) + j) + k):

a + i: i + 1个二维数组的地址。

*(a + i): i + 1个二维数组的首个一维数组的地址。

*(a + i) + j: i + 1个二维数组的第j + 1个一维数组的地址。

*(*(a + i) + j): i + 1个二维数组的第j + 1个一维数组的首元素的地址。

*(*(a + i) + j) + k: i + 1个二维数组的第j + 1个一维数组的第k + 1个元素的地址。

*(*(*(a + i) + j) + k): i + 1个二维数组的第j + 1个一维数组的第k + 1个元素的值。

 

*(&a) = a;对三维数组的地址取值等于首个二维数组的地址。

 

 

拓展:当函数传参时,对每个数组的正确传法。

 

传递一维数组名时, 用元素指针来接收,  如:*ptr

传递二维数组名时,用二维数组指针来接收,  如:(*ptr)[ ] 标明具体多少列。

传递三维数组名时,用二维数组指针来接收。  如:(*ptr)[ ][ ] 标明行列号。

 

指针数组:

定义:int *pa[3];

      int i;

      for(i = 0; i < 3; i++);

      {

  pa[i] = (int *)malloc((sizeof(int));   //给指针分配内存

  scanf(“%d”,pa[i]);

  printf(“pa[%d] = %d\n”,i, *(pa[i]));

         }

 

用法: 当传参为指针数组时,用指针的指针来接收。

 如: print_ptr(ptr);  -------->   void print_ptr(char **ptr)

 

总结:指针与数组的区别

1);空间分配上:  数组:静态分配。    指针:动态分配。

2)访问效率上:    数组:直接访问。    指针:间接访问。

3)安全性上:      数组:易造成数组越界。  指针:易造成内存泄漏。

4)形参:   数组默认转化成指针

5)使用上: 数组操作的是值。  指针操作的是地址。

6)分配空间上: 数组空间连续。  指针:地址空间不一定连续

拓展:

 二叉树的基本选择原则;

 先序: 根 、 左树 、右树

 中序:左树 、根 、右树

 后序:左树 、右树 、根

 

 

堆排:如果堆的有序状态因某个节点变得比它的父节点更大而被打破,那么就需要通过交换

      它和它的父节点来修复堆,从最后一个非节点逐渐往上浮,直到有序。

 

如: 打乱的堆(5  11  7  2  3  17) 利用堆排来初始化堆

                                      

       5                              5                               17                          17

 

  11       7                  11    17                      11    5                      11    7

 

2   3     17               2     3    7                   2   3    7                  2     3    5

 

最后得到堆(17  11  7  2  3  5


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值