malloc(0)返回什么地址?

本文探讨了C语言中malloc(0)的行为,依据C99标准解释了其可能返回空指针或非空指针的原因,并通过实验验证了malloc(0)返回地址的特点。
 
问题内容: malloc(0)返回什么地址?
  • 原讨论链接: http://community.youkuaiyun.com/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作为额外的指针什么的

### ### malloc 内存分配原理及其实现机制 `malloc` 是 C 语言中用于动态分配内存的核心函数之一,其设计目标是提供一种高效的内存管理机制,使程序能够在运行时按需分配和释放内存[^3]。其工作原理基于堆(heap)区域的管理,涉及复杂的内存分配策略、碎片处理机制以及性能优化。 #### 内存分配的基本机制 `malloc` 函数通过调用底层系统调用来扩展程序的堆空间。在 Linux 系统中,`malloc` 通常使用 `brk` 或 `mmap` 系统调用来获取新的内存区域。首次调用 `malloc` 时,运行时库会通过 `brk(0)` 获取当前堆的结束地址,然后使用 `brk` 增加堆的大小来分配新的内存空间[^4]。后续的 `malloc` 调用则会利用已分配的堆空间进行内存管理,而不是每次都调用系统调用,这样可以提高性能。 #### 内存管理与分配器设计 `malloc` 的实现通常基于一个内存分配器,它负责在堆中维护空闲内存块,并在请求时返回合适的内存块。分配器需要在多个方面进行权衡,包括分配速度、内存利用率、碎片管理等。常见的策略包括: - **首次适配(First Fit)**:从内存块的起始位置开始查找第一个足够大的空闲块。 - **最佳适配(Best Fit)**:查找最小的足够大的空闲块,以减少浪费。 - **分离空闲列表(Segregated Free List)**:将空闲块按大小分类管理,加快分配速度。 为了减少内存碎片,`malloc` 实现中通常包含合并相邻空闲块的机制。例如,当一个内存块被释放时,分配器会检查其前后是否有空闲块,并将它们合并成一个更大的块,以提高后续分配的效率[^3]。 #### 内存释放与碎片管理 `free` 函数用于释放由 `malloc` 分配的内存。释放内存时,分配器需要将内存块标记为空闲,并尝试与相邻的空闲块合并,以减少外部碎片。这种机制可以提高内存的利用率,避免因频繁分配和释放导致的内存浪费。 #### 性能优化与实现细节 现代 `malloc` 实现通常包含多种优化策略,以提高性能和内存利用率。例如: - **缓存小块内存**:对于频繁分配的小内存块,分配器可能会维护一个专门的缓存池,以减少分配开销。 - **线程局部存储**:在多线程环境中,`malloc` 实现通常会为每个线程维护独立的内存池,以减少锁竞争,提高并发性能。 - **延迟合并**:为了避免频繁的合并操作影响性能,某些分配器会在特定条件下才进行内存块的合并。 #### 示例代码 以下是一个简单的示例,展示了 `malloc` 和 `free` 的基本用法: ```c #include <stdio.h> #include <stdlib.h> int main() { int *array = (int *)malloc(10 * sizeof(int)); if (array == NULL) { fprintf(stderr, "Memory allocation failed\n"); return 1; } for (int i = 0; i < 10; i++) { array[i] = i * i; } for (int i = 0; i < 10; i++) { printf("%d ", array[i]); } printf("\n"); free(array); return 0; } ``` 这段代码首先使用 `malloc` 分配了 10 个整型大小的内存空间,然后对数组进行初始化并打印,最后使用 `free` 释放内存。 ###
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值