C语言中的内存分配深入(二)

C语言中的内存分配深入()

紧接上一篇文章讲,上次讲的内存分配这里讲分配的内存的回收的问题。

对于指针以前就说过了,没有赋值地址的指针是不可以写的,这里就给一个更加深入的说法:

第一、指针指向一个地址,因此,在不管以后写或是不写的情况下,它可以指向任何一个地址,而且都是可以的,比如:

   int *p , a, b;

   p = &a;

   p = &b;

即便是ab都没有分配值,但是它的地址是存在的;

第二、上面的那种情况是有局限性的,他的成立条件就是系统已经给这个指针分配好4个字节的情况,因此,也并不是所有的指针都可以任意指向,当一个指针以另外一个对象的指针的形式存在的时候,指针的4个字节是确定的了,同情况一,但是作为指针的内部指针存在的时候,分给指针的4个字节的空间就不是那么的明朗了,这个时候就牢记一点,这个4个字节也是指针的内部值,在没有大的指针分配地址空间的时候,内部依旧不可以写,那么这个小的内部指针也是不可以写的,因此它不可以指向任何地址!

#include <stdio.h> 

#include <malloc.h> 

typedef struct sim { 

 sim *next; 

}sim ;

 int main() { 

 sim *d = (sim *)malloc(sizeof(sim) ); 

 sim e;   

e.next = d; //next要用到的4字节空间已经随着e对象的系统自动分配产生,因此可以写!  

sim *a = &e; //也是可以的,独立的指针,要用到的用于存放指针的4个字节空间也是分配好的  

sim *b;  b->next = &e; //Oh, b认为是一个独立的指针,并没有分配一个sim大小的空间,内部自然不可写       

                 //即便next是指针,他的4字节空间不确定,编译通过,运行失败! 

}

 

 

#include <stdio.h>

#include <malloc.h>

typedef struct sim {

	sim *next;

}sim ;

int main() {

	sim *d = (sim *)malloc(sizeof(sim) ); 

	sim e;	

	e.next = d; //next要用到的4字节空间已经随着e对象的系统自动分配产生,因此可以写!

	sim *a = &e; //也是可以的,独立的指针,要用到的用于存放指针的4个字节空间也是分配好的

	sim *b;

	b->next = &e; //Oh, b认为是一个独立的指针,并没有分配一个sim大小的空间,内部自然不可写

				  //即便next是指针,他的4字节空间不确定,编译通过,运行失败!

}

因此还是那句话,指针没有分配地址空间的时候,内部不可写!

 

 

我们看一个链表的错误的删除操作,而且这种操作我在好多地方见过,如下:

{    // ……   list p;  // p is a list object created with head and lnode is the node of the list!   lnode current  =  p -> head;    // delete opration    while  (current  !=   NULL) {      free(current);      current  =  current -> next;   }    // …… }

 

 

这里问题就出来了,currentfree之后,他的next还可以指向他之前指向的那个对象否?那他的自带的值还可以被写否?

 

前者是否定的,后者是不一定,一般的情况甚至是肯定的。

首先补充一点,就是一个指针也特别结构体指针,在没有分配地址空间的时候,不管是对象还是指针都是不可以写的,指针可以写NULL。如下,malloc的头文件在vs2005要代malloc.h头文件,linuxgcc编译器只要stdio.h就可以了:

#include  < stdio.h > #include  < malloc.h > typedef  struct  simple {    int  test;   simple  * next; }simple ; int  main() {   simple  * a,  * b,  * c;   a -> test  =   100 ;   a -> next  =  b; }

 

这个程序在vs2005里面运行就是一个很响亮的linux下就是程序中断得到一个段错误。

回到上面的问题,既然free了那就相当于没有分配空间,肯定也就不能写哦,为什么答案是可以写呢(一般情况下)?

这样,我们创建一个小链表,就两个对象,ab,让anext指向b,然后free释放a,再看看:

#include  < stdio.h > #include  < malloc.h > typedef  struct  simple {    int  test;   simple  * next; }simple ; int  main() {   simple  * a,  * b,  * c;    a  =  (simple  * )malloc( sizeof (simple) );   b  =  (simple  * )malloc( sizeof (simple) );   c  =  (simple  * )malloc( sizeof (simple) );    a -> test  =   100 ;   b -> test  =   200 ;   c -> test  =   300 ;   a -> next  =  b;   b -> next  =  NULL;   c -> next  =  NULL;   printf( " The addr of a is %d ! " , ( void   * )a);   printf( " The addr of b is %d ! " , ( void   * )b);   printf( " The addr of c is %d ! " , ( void   * )c);   printf( " The addr of a->next is %d ! " , ( void   * )a -> next );   printf( " The number of a->test is %d ! " , (a -> test));   printf( " The addr of a->test is %d ! " , ( void   * ) & (a -> test));   puts( "" );   free(a);   printf( " The addr of a is %d ! " , ( void   * )a);   printf( " The addr of b is %d ! " , ( void   * )b);   printf( " The addr of c is %d ! " , ( void   * )c);   printf( " The addr of a->next is %d ! " , ( void   * )a -> next);   printf( " The number of a->test is %d ! " , (a -> test));   printf( " The addr of a->test is %d ! " , ( void   * ) & (a -> test));   puts( "" );   a -> next  =  c;   a -> test  =   100 ;   printf( " The addr of c is %d ! " , ( void   * )a -> next);   printf( " Test is %d  " , b -> test);    return   0 ; }

 

程序输出:

The addr of a  is   3887080   ! The addr of b  is   3876984   ! The addr of c  is   3877040   ! The addr of a -> next  is   3876984   ! The number of a -> test  is   100   ! The addr of a -> test  is   3887080   !   The addr of a  is   3887080   ! The addr of b  is   3876984   ! The addr of c  is   3877040   ! The addr of a -> next  is   - 572662307   ! The number of a -> test  is   - 572662307   ! The addr of a -> test  is   3887080   ! The addr of c  is   3877040   ! Test  is   200

 

 

在这个程序里面我们就看到了,free之前,a的内容如下:

 

The addr of a->next is 3876984 !

The number of a->test is 100 !

The addr of a->test is 3887080 !

free之后,内容如下: The addr of a->next is -572662307 !

The number of a->test is -572662307 !

The addr of a->test is 3887080 !

testnext的值都已经变化了,但是从test的地址可以看出a并没有从原来的地址撤兵,他依旧指向他以前的地址,但是有一点很明显就是a里面的所有的值都已经变化,而且是很奇怪了。

这里就回答了前面的两个问题,free之后的对象不再指向他原来的值,但是他依旧可以写,但是,如果他用的这个内存在此被分配给别的变量的时候,就不再可写了。

再回到最上面的delete操作,再上面的这段程序里面加点东西,让a的地址变为anext,开始已经知道了,next已经变了,但是还是可写的。

如下:

#include  < stdio.h > #include  < malloc.h > typedef  struct  simple {    int  test;   simple  * next; }simple ;  int  main() {   simple  * a,  * b,  * c;    a  =  (simple  * )malloc( sizeof (simple) );   b  =  (simple  * )malloc( sizeof (simple) );   c  =  (simple  * )malloc( sizeof (simple) );    a -> test  =   100 ;   b -> test  =   200 ;   c -> test  =   300 ;   a -> next  =  b;   b -> next  =  NULL;   c -> next  =  NULL;   printf( " The addr of a is %d ! " , ( void   * )a);   printf( " The addr of b is %d ! " , ( void   * )b);   printf( " The addr of c is %d ! " , ( void   * )c);   printf( " The addr of a->next is %d ! " , ( void   * )a -> next );   printf( " The number of a->test is %d ! " , (a -> test));   printf( " The addr of a->test is %d ! " , ( void   * ) & (a -> test));   puts( "" );   free(a);    printf( " The addr of a is %d ! " , ( void   * )a);   printf( " The addr of b is %d ! " , ( void   * )b);   printf( " The addr of c is %d ! " , ( void   * )c);   printf( " The addr of a->next is %d ! " , ( void   * )a -> next);   printf( " The number of a->test is %d ! " , (a -> test));   printf( " The addr of a->test is %d ! " , ( void   * ) & (a -> test));   puts( "" );   a  =  a -> next;   a -> next  =  c;   a -> test  =   100 ;   printf( " The addr of c is %d ! " , ( void   * )a -> next);   printf( " Test is %d  " , b -> test);    return   0 ; }

 

 

这样一来,在执行到a->next = c的时候程序崩溃,a指向了一个不可写的地址,a = a->next不会崩溃,因为这里只是改变了一个地址值,而不是写内存。

 

解决方案:

对于free了的指针,我们补上一句话,用NULL给它赋地址!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值