堆内存管理:
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:每块的字节数
返回值:申请的内存块的首地址
- 该函数其实底层调用的是malloc分配的是一整块内存,nmemb、size参数只是增加了了代码的可读性,nmemb、size实参交换位置后不影响最后的结果
- 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函数?
操作系统运行效率更高