📅  最后修改于: 2023-12-03 15:13:46.097000             🧑  作者: Mango
C语言中提供了一种动态内存分配的方式,即 malloc 函数。它的作用是在程序运行时从堆(heap)中分配指定大小的内存空间,返回该空间的首地址。它的函数原型如下:
void *malloc(size_t size);
其中,参数 size 是要分配的内存空间字节数,函数返回的是一个指向 void 类型的指针,需要根据实际的类型进行强制类型转换。
使用方法如下:
int *p = (int*)malloc(sizeof(int)*10);
这样就分配了一个能够存放 10 个 int 类型数据的内存空间,并将首地址赋给指针变量 p。
需要注意,使用完 malloc 分配的内存空间后,需要调用 free 函数进行释放,否则会出现内存泄漏。
下面我们来实现一个简单的 malloc 函数。
首先,我们需要定义一个动态分配内存的空间池,用来存储已经分配的内存块,这里使用一个链表来实现。链表的每个节点都表示一个内存块,包括该内存块的大小和指向该内存块首地址的指针。
typedef struct _mem_block mem_block;
typedef struct _mem_block {
size_t size; // 内存块大小
mem_block *next; // 指向下一个内存块
} mem_block;
mem_block *head = NULL; // 内存块链表头指针
接下来我们可以实现简单的 malloc 函数。它的实现思路很简单,就是遍历内存块链表,查找第一个大小大于等于需求大小的内存块。如果找到了,就从该内存块中分离出需要的大小,返回指向该内存块起始位置的指针,并将剩余部分插入到链表中。
void* malloc(size_t size) {
mem_block *p, *prev = NULL;
void *ret = NULL;
for (p = head; p != NULL; prev = p, p = p->next) {
if (p->size >= size) { // 找到了合适大小的内存块
if (p->size - size >= sizeof(mem_block)) { // 剩余部分足够大,可以分离出来
mem_block *tmp = (mem_block*)((char*)p + size); // 分离部分的内存块
tmp->size = p->size - size - sizeof(mem_block);
tmp->next = p->next;
if (prev == NULL) { // 在链表头上进行插入
head = tmp;
} else {
prev->next = tmp;
}
} else { // 剩余部分过小,整块分配出去
if (prev == NULL) { // 链表头节点
head = p->next;
} else {
prev->next = p->next;
}
}
ret = (void*)(p + 1);
break;
}
}
if (p == NULL) { // 找不到合适大小的内存块
p = (mem_block*)sbrk(sizeof(mem_block) + size); // 通过 sbrk 申请空间
if (p == (void*)-1) { // 申请失败
return NULL;
} else { // 申请成功
p->size = size;
p->next = head;
head = p;
ret = (void*)(p + 1);
}
}
return ret;
}
需要注意的是,为了方便我们使用了系统调用 sbrk 来申请动态内存,需要包含头文件 unistd.h。
最后,别忘了实现 free 函数来释放已经分配的内存块!
以上就是一个简单的手写 malloc 函数的实现过程。