malloc(0)返回什么地址?

来源:互联网 发布:java个人博客建站 编辑:程序博客网 时间:2024/05/23 21:55
问题内容:malloc(0)返回什么地址?
原讨论链接:http://community.csdn.net/expert/topicview1.asp?id=4351400
所属论坛:C语言 审核组:C/C++
提问者:jidahyx 解决者:steedhorse
感谢:steedhorse
关键字:
答案:

char *p = (char *)malloc(0); 
strcpy(p, "hello"); 
printf("%s\n",p); 
free(p); 
其中,p中的地址是堆内的首地址? 
--------------------------------------------------------------- 

C99标准(ISO/IEC 9899:1999 (E))上说: 

If the size of the space requested is zero, the behavior is implementationdefined: 
either a null pointer is returned, or the behavior is as if the size were some 
nonzero value, except that the returned pointer shall not be used to access an object.

如果所请求的空间大小为0,其行为由库的实现者定义:可以返回空指针,也可以让效果跟申请某个非0大小的空间一样,所不同的是返回的指针不可以被用来访问一个对象。

为什么 new T[0] 和 malloc(0) 不返回空指针

首先需要说明的是,按照C++标准,成功的 new T[0] 是不能返回空指针的。而 malloc(0),C 语言标准则指出,成功的时候可以返回空指针,也可以返回非空指针,多数库一般也选择了返回非空指针这种行为。

为什么这么做呢?
1. 理念:0大小的对象也是对象。
2. 实践:返回空会和分配失败混淆,尤其是大小是计算出来的时候,这时如果得到的是空指针,用户程序会误以为分配失败了。
3. 实现:反正返回的地址不能读写,此时可以返回同一个固定的地址,并没什么额外开销。而且多数编译器,C和C++一起提供,C++库的new也用C库的malloc实现,使二者保持一致也比较省事。
4.不管返回的是不是空,都可以free的。

测试程序如下

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
char *ptr;
printf("0x%x\n", ptr); // this line will cause seg fault sometimes

printf("----malloc 0 4 times----\n");
ptr = (char *)malloc(0);
printf("0x%x\n", ptr);

ptr = (char *)malloc(0);
printf("0x%x\n", ptr);

ptr = (char *)malloc(0);
printf("0x%x\n", ptr);

ptr = (char *)malloc(0);
printf("0x%x\n", ptr);

printf("----malloc 1 4 times----\n");
ptr = (char *)malloc(1);
printf("0x%x\n", ptr);

ptr = (char *)malloc(1);
printf("0x%x\n", ptr);

ptr = (char *)malloc(1);
printf("0x%x\n", ptr);

ptr = (char *)malloc(1);
printf("0x%x\n", ptr);

printf("----malloc 4 4 times----\n");
ptr = (char *)malloc(4);
printf("0x%x\n", ptr);

ptr = (char *)malloc(4);
printf("0x%x\n", ptr);

ptr = (char *)malloc(4);
printf("0x%x\n", ptr);

ptr = (char *)malloc(4);
printf("0x%x\n", ptr);

printf("----malloc 16 4 times----\n");
ptr = (char *)malloc(16);
printf("0x%x\n", ptr);

ptr = (char *)malloc(16);
printf("0x%x\n", ptr);

ptr = (char *)malloc(16);
printf("0x%x\n", ptr);

ptr = (char *)malloc(16);
printf("0x%x\n", ptr);

printf("----malloc 32 4 times----\n");
ptr = (char *)malloc(32);
printf("0x%x\n", ptr);

ptr = (char *)malloc(32);
printf("0x%x\n", ptr);

ptr = (char *)malloc(32);
printf("0x%x\n", ptr);

ptr = (char *)malloc(32);
printf("0x%x\n", ptr);

printf("----malloc 64 4 times----\n");
ptr = (char *)malloc(64);
printf("0x%x\n", ptr);

ptr = (char *)malloc(64);
printf("0x%x\n", ptr);

ptr = (char *)malloc(64);
printf("0x%x\n", ptr);

ptr = (char *)malloc(64);
printf("0x%x\n", ptr);

return 0;
}

系统表现如下:
root@dell:~/test# ./a.out .
0xd27fb840
----malloc 0 4 times----
0x8060f38
0x8060f48
0x8060f58
0x8060f68    diff=0x10=16B
----malloc 1 4 times----
0x8060f78
0x8060f88
0x8060f98
0x8060fa8    diff=0x10=16B
----malloc 4 4 times----
0x8060fb8
0x8060fc8
0x8060fd8
0x8060fe8    diff=0x10=16B
----malloc 16 4 times----
0x8061340
0x8061358
0x8061370
0x8061388    diff=0x18=24B
----malloc 32 4 times----
0x8061948
0x8061970
0x8061998
0x80619c0    diff=0x28=40B
----malloc 64 4 times----
0x8062348
0x8062390
0x80623d8
0x8062420    diff=0x48=72B

第一个是0xdxxx是因为指针变量在建栈的时候已经在栈上获得4B的一个空间,而空间里面的值,应该是随机的
不过不晓得为什么总指在同一个地方?

malloc在ics(introduction to computer science)中讲过,除了分出来的空间之外,为了维护整个堆结构,并考虑时间,空间效果
其或头,或尾,或头尾,均有额外的指针结构存在
分析16,32,64B的情况可知,多余的部分为8B,猜测是头尾各4B

然后再看,0,1,4的时候都是16B,说明每次分配的时候有个最小下限
也就是起板就是8B作为分出来的数据,另外8B作为额外的指针什么的

 原文地址 http://blog.csdn.net/zhongjiekangping/archive/2010/08/13/5810124.aspx


额外:
ANSI C的,如果认为malloc(0)是语法错误的话,下面我写的就不用看了。
下面进入正题,关于malloc(0)这个问题,我在网上看到有个面试题好像就是问这个的,原题好像是:
char *ptr; 
if ((ptr = (char *)malloc(0)) == NULL) 
puts("Got a null pointer"); 
else 
puts("Got a valid pointer"); 
该代码的输出是“Got a valid pointer”,不信的可以尝试下!只给出答案,但没给出具体的原理解答。

下面我说一下关于这个题目的尝试情况:
正常在指针的引用时候,如果定义char *str = NULL;后如果不对其进行malloc的话,执行memcpy(str,"hello",strlen("hello"))是会出现错误的,而且malloc的空间必须要大于等于strlen("hello")。正常的malloc一个大于0的长度,会在堆区分配一段空间来供程序员使用,memcpy等等。理论上来说如果想要赋值一个字符串到目标指针执行的空间,这个指针指向的空间必须有足够的“大小”来存储。按照malloc(a)函数的说明,malloc错误会返回一个NULL指针,如果执行成功会返回一个大小为a的空间,malloc(0)如果可以成功执行,则应该在堆区分配一个大小为0的空间,但我尝试往这个空间赋值,会发现无论你要复制的字符串有多长都可以复制进去,和正常的malloc(strlne(str))这样不同的是这个空间无法通过free来释放掉,free(str)就会报错。


基本情况就是这样,我想知道啊这个空间具体是什么位置的,为什么没有大小限制可以往里面无限赋值,这里有没有人研究过这问题,一起来讨论下!

首先来解释malloc(0)的问题,这个语法是对的,而且确实也分配了内存,但是内存空间是0,就是说返回给你的指针是不能用的,感觉奇怪吧?但是从操作系统的原理来解释就不奇怪了,这要涉及操作系统维护内存的方法来说了,在内存管理中,内存被分为2部分,栈和堆,栈有自己的机器指令,是一个先进后出的数据结构,我就在这里不再过多解释了,malloc分配的内存是堆内存,由于堆没有自己的机器指令,所以要有系统自己编写算法来管理这片内存,通常的做法是用链表,在每片被分配的内存前加个表头,里面存储了被分配内存的起始地址和大小,你的malloc返回的就是表头里的起始指针,这个地址是由一系列的算法得来了,通常不会为0,一旦分配成功,就返回一个有效的指针,对于分配0空间来说,算法已经算出可用内存的起始地址,但是你占用0空间,所以对那个指针操作就是错误的,操作系统一般不知道其终止地址,因为有占用大小就可以推出终止地址,还有就是即使分配0空间也要释放它,其实是释放的链表结点

还有,返回的指针是可用地址的起始地址,虽然你可以无限赋值,但是其实是错误的,因为可能有其他有用的数据在那一片区域,如果指针越界就会出现意想不到的事情,不懂的再问
0 0
原创粉丝点击