堆内存管理:

C语言中没有管理堆内存的语句,而是由标准库提供一套函数来管理堆内存,calloc、free、malloc、realloc。

malloc

include

void *malloc( size_t size );
功能:向系统申请一块堆内存
size:内存块的字节数
返回值:
成功 返回内存块的首地址
失败 返回NULL

bzero

使用malloc申请的内存,里面的内存是随机的、不确定的,如果需要对内存进行初始化可以使用以下函数:
#include <strings.h>
void bzero(void *s, size_t n);
功能:把一块内存的所有字节赋值为0
s:内存的首地址
n:内存块的字节数

memset

void *memset(void *s, int c, size_t n);
功能:把一块内存的所有字节赋值为c
s:内存的首地址
c:要赋值的数据,范围:0~255
n:内存块的字节数

当首次向malloc申请内存时,malloc会向操作系统申请内存,操作系统会直接分配33页(1页=4096字节)内存交给malloc来管理

malloc分配的内存块之间有一些空隙(4~12字节),这些空隙中存在一个指针,这个指针所指向的空间记录malloc的管理信息,一旦破坏就会影响接下来malloc和free的使用。

不要越界,要回查询,若有错误就去往上寻找错误

free

void free(void **ptr);

功能:释放内存

注意: 1. 可以释放空指针

2.不可以重复释放

3.只释放使用权,不会清理释放的内存

操作系统对堆内存的管理决定了是否产生段错误,而malloc、free只是管理堆内存的使用权限,这两个是函数只是管理不会直接报错。如果越界访问,可能会影响malloc、free的后续使用,也可能会产生脏数据。

malloc(sizeof(int)10);
calloc(10,sizeof(int));
calloc

void *calloc(size_t nmemb,size_t size);

void *calloc(size_t nmemb,size_t size)
{
    void* ptr = malloc(size=nmemb);
    bzero(ptr,size*nmemb);
    return ptr;
}

功能:按块分配堆内存,'且会初始化为0

nmemb:要申请的块数(逻辑上的块,不是物理上的块数 )

size:每块的字节数

返回值:申请的内存块的首地址

  1. 该函数其实底层调用的是malloc分配的是一整块内存,nmemb、size参数只是增加了了代码的可读性,nmemb、size实参交换位置后不影响最后的结果
  2. calloc会把分配的内存进行初始化为0,因为速度会比malloc更慢
realloc

void *realloc (void *ptr, size_t size);

功能:调整已经申请到的内存块大小,可以往大里调整,也可以往小里调整

ptr:申请到的内存块首地址

size:最终内存块的字节数

返回值:调整后的内存块首地址,如果在原块的基础上无法调整,realloc会重新申请一块size个字节的内存,然后把原ptr的内容拷贝,再把ptr释放

问题:

int* p = malloc(4);

int i = 0;

for(;😉

{

printf("%d\n",i);

p[i] = i++;

}


1、为可以越界那么多?
当首次向malloc申请内存时,malloc会向操作系统申请内存,操作系统会直接分配33页(1页=4096字节)内存交给malloc来管理
2、为什么是33790才产生段错误?
会分配4个字节是用来记录malloc的维护信息,(33*4096-4)/4=33791,因为从0开始计数,所以到33790才产生段错误
3、为什么这样设计malloc函数?
操作系统运行效率更高