📜  C mallo - C 编程语言(1)

📅  最后修改于: 2023-12-03 15:13:46.097000             🧑  作者: Mango

C语言中的动态内存分配——malloc

C语言中提供了一种动态内存分配的方式,即 malloc 函数。它的作用是在程序运行时从堆(heap)中分配指定大小的内存空间,返回该空间的首地址。它的函数原型如下:

void *malloc(size_t size);

其中,参数 size 是要分配的内存空间字节数,函数返回的是一个指向 void 类型的指针,需要根据实际的类型进行强制类型转换。

使用方法如下:

int *p = (int*)malloc(sizeof(int)*10);

这样就分配了一个能够存放 10 个 int 类型数据的内存空间,并将首地址赋给指针变量 p。

需要注意,使用完 malloc 分配的内存空间后,需要调用 free 函数进行释放,否则会出现内存泄漏。

手写简单的 malloc 函数

下面我们来实现一个简单的 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 函数的实现过程。