malloc(0)

最近看到一个很奇怪的问题,就是malloc(0),返回的却不是NULL,但是free这块内存时却报错。

程序跑起来的内存可以分为栈和堆,栈有自己的机器指令,是一个先进后出的数据结构,我就在这里不再过多解释了,malloc分配的内存是堆内存,由于堆没有自己的机器指令,所以要有系统自己编写算法来管理这片内存,通常的做法是用链表,在每片被分配的内存前加个表头,里面存储了被分配内存的起始地址和大小,你的malloc返回的就是表头里的起始指针,这个地址是由一系列的算法得来了,通常不会为0,一旦分配成功,就返回一个有效的指针,对于分配0空间来说,算法已经算出可用内存的起始地址,但是你占用0空间,所以对那个指针操作就是错误的,操作系统一般不知道其终止地址,因为有占用大小就可以推出终止地址,还有就是即使分配0空间也要释放它,其实是释放的链表结点。还有,返回的指针是可用地址的起始地址,可用大小是固定的,在VC6下是56字节,这个大小可能就是链表节点的大小,做了一个验证,代码如下:

int main()
{
 char *ptr =NULL;
 char *ptr2 = NULL;
 char *ptr3 = NULL;

 ptr = malloc(0*sizeof(char)) ;
 ptr2 = malloc(32*sizeof(char));
 ptr3 = malloc(32*sizeof(char));

 //strcpy(ptr,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
 strcpy(ptr2, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
 strcpy(ptr3, "ccccccccccccccccccccccccccccccc");

 printf("ptr : %x\n", ptr);
 printf("ptr2 : %x\n", ptr2);
 printf("ptr3 : %x\n", ptr3);
 
 if (NULL == ptr)
  printf("got a NULL pointer\n");
 else
 {
  printf("got a Valid pointer\n");
  // 有56个a,另外有一个字节用于保存''\0'
  //strcpy(ptr,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
   strcpy(ptr,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

  //printf("the value at %X is:%c\n",ptr,*ptr);
  //printf("the string at %x is :%s\n",ptr, ptr);
    printf("the string ptr: %s\n", ptr);
    printf("the string ptr2: %s\n", ptr2);
    //printf("the string ptr2 + 56: %s\n", ptr2 + 56);
    printf("the string ptr3: %s\n", ptr3);

  //free(ptr);
 }
 return 0 ;

}

结果如下:


malloc(0)之后在malloc(32),两者返回的地址刚好相差56byt,应该就是VC6.0的维护内存的节点的大小了,然后ptr3的地址跟ptr2相差88(56 + 32)。


综合上面的验证,可以得出一个这样的结论,如果malloc成功,返回的其实是管理筷链表的起始地址,这个地址是不会为0的,但是可以使用的地址确是0,以为ptr2的地址为ptr+56,malloc真实使用的地址是malloc返回的地址加上头大小56开始,到sizeof地址处结束。超出这个范围的访问就是越界了


发布了22 篇原创文章 · 获赞 9 · 访问量 8834

猜你喜欢

转载自blog.csdn.net/ljm_c_bok/article/details/80298797