Malloc

本文探讨了在C语言中使用malloc函数分配零字节内存的行为。通过实验发现,即使请求分配的字节数为零,malloc仍可能返回一个有效指针。文章还讨论了在编程实践中如何避免此类不确定状态。

       首先提出一个问题,如果使用malloc申请分配内存的时候,如果传入的字节长度为0,会出现一个什么样的情况?函数会出错吗?如果不会出错,那么又会返回一个什么样的值?是NULL吗?
        刚刚遇到这个问题,我也很疑惑,于是作了个简单的例子作测试:在VC6.0中测试
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

int main()
{
char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
    printf("Got a null pointer");
else
{
    printf("Got a valid pointer/n");
 printf("The malloc address is  %#x/n",long(ptr));
}
return 0;
}

结果发现,几乎每次都能够输出
Got a valid pointer
The malloc address is 0x430160
结果比较出乎我的意料,于是我查阅资料,终于找到问题的答案:
C语言中在内存分配的时候有两种不确定的状态:
1.如果申请分配内存的长度为零,那么返回的值不确定
2.内存分配成功之后,如果没有初始化,那么分配空间里的值是不确定

知道这两种情况后,我们在编程的时候就可以避免出现传入申请长度为零的内存,并且在申请之后进行初始化。

### 使用方法 `malloc` 函数的功能是开辟指定字节大小的内存空间,如果开辟成功就返回该空间的首地址,如果开辟失败就返回一个 `NULL`。传参时只需传入需要开辟的字节个数。由于 `malloc` 函数的返回值为 `void*`,所以需要强制类型转换为对应类型。 示例代码如下: ```c #include <stdio.h> #include <stdlib.h> int main() { int* p = (int*)malloc(10 * sizeof(int)); if (p == NULL) { printf("内存开辟失败\n"); } else { printf("内存开辟成功\n"); // 使用... // 使用结束,释放内存 free(p); p = NULL; } return 0; } ``` 注:`malloc` 函数开辟好空间后,不对空间内容做任何初始化,所以空间内的数据为随机值[^5]。 ### 原理 `malloc` 基本的实现原理是维护一个内存空闲链表,当申请内存空间时,搜索内存空闲链表,找到适配的空闲内存空间,然后将空间分割成两个内存块,一个变成分配块,一个变成新的空闲块。如果没有搜索到,那么就会用 `sbrk()` 推进 `brk` 指针来申请内存空间。搜索空闲块最常见的算法有首次适配、下一次适配、最佳适配: - 首次适配:第一次找到足够大的内存块就分配,这种方法会产生很多的内存碎片。 - 下一次适配:等第二次找到足够大的内存块就分配,这样会产生比较少的内存碎片。 - 最佳适配:对堆进行彻底的搜索,从头开始,遍历所有块,使用数据区大小大于 `size` 且差值最小的块作为此次分配的块 [^2]。 默认情况下,`malloc` 函数分配内存,如果请求内存大于 128K(可由 `M_MMAP_THRESHOLD` 选项调节),那就不是去推 `_edata` 指针了,而是利用 `mmap` 系统调用,从堆和栈的中间分配一块虚拟内存 [^4]。 `malloc` 函数有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用 `malloc` 函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用 `free` 函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,`malloc` 函数请求延时,并开始在空闲链上检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。如果无法获得符合要求的内存块,`malloc` 函数会返回 `NULL` 指针,因此在调用 `malloc` 动态申请内存块时,一定要进行返回值的判断 [^3]。 ### 应用场景 - **动态数组**:当程序运行时才知道需要的数组大小,可使用 `malloc` 动态分配内存。例如,读取文件中的数据,在不知道文件中有多少数据项的情况下,可使用 `malloc` 动态分配足够的内存来存储这些数据。 - **链表、树等动态数据结构**:这些数据结构的节点需要在运行时动态创建和销毁,使用 `malloc` 可以方便地分配和释放节点所需的内存。 - **大型数据处理**:在处理大型图像、音频、视频等数据时,可能需要在运行时动态分配大量的内存来存储和处理这些数据。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值