我想知道malloc和free是怎么工作的。

int main() {
    unsigned char *p = (unsigned char*)malloc(4*sizeof(unsigned char));
    memset(p,0,4);
    strcpy((char*)p,"abcdabcd"); // **deliberately storing 8bytes**
    cout << p;
    free(p); // Obvious Crash, but I need how it works and why crash.
    cout << p;
    return 0;
}

如果答案是在记忆层面上的深度,如果可能的话,我会非常感激。


当前回答

这与malloc和free没有特别的关系。你的程序在复制字符串后表现出未定义的行为——它可能在那一点或之后的任何一点崩溃。即使您从未使用malloc和free,并在堆栈上或静态地分配char数组,也会出现这种情况。

其他回答

How malloc() and free() works depends on the runtime library used. Generally, malloc() allocates a heap (a block of memory) from the operating system. Each request to malloc() then allocates a small chunk of this memory be returning a pointer to the caller. The memory allocation routines will have to store some extra information about the block of memory allocated to be able to keep track of used and free memory on the heap. This information is often stored in a few bytes just before the pointer returned by malloc() and it can be a linked list of memory blocks.

通过写入超过malloc()分配的内存块,您很可能会破坏下一个块的一些簿记信息,这些信息可能是剩余的未使用的内存块。

在向缓冲区复制太多字符时,程序也可能崩溃。如果额外的字符位于堆之外,当您试图写入不存在的内存时,可能会遇到访问冲突。

Malloc和free依赖于实现。典型的实现包括将可用内存划分为“空闲列表”——可用内存块的链表。许多实现人为地将它分为小对象和大对象。空闲块以内存块有多大以及下一个内存块在哪里等信息开始。

当你malloc时,一个块从空闲列表中拉出来。当你释放时,块被放回空闲列表。很有可能,当你重写指针的末尾时,你是在写空闲列表中一个块的头。当您释放内存时,free()尝试查看下一个块,并可能最终击中导致总线错误的指针。

同样重要的是要意识到,简单地使用brk和sbrk移动程序断点指针实际上并不分配内存,它只是设置了地址空间。例如,在Linux上,当访问该地址范围时,内存将由实际的物理页“备份”,这将导致页错误,并最终导致内核调用页分配器以获得备份页。

这很难说,因为不同的编译器/运行时之间的实际行为是不同的。即使是调试/发布版本也有不同的行为。VS2005的调试版本将在分配之间插入标记来检测内存损坏,因此它将在free()中断言,而不是崩溃。

这与malloc和free没有特别的关系。你的程序在复制字符串后表现出未定义的行为——它可能在那一点或之后的任何一点崩溃。即使您从未使用malloc和free,并在堆栈上或静态地分配char数组,也会出现这种情况。