1. 内存的四区模型
2. 动态内存管理
由上图可知,属于程序员管理的内存空间只有堆区,所以动态内存管理都是在堆区进行的。
1). 动态内存管理的意义
通过局部变量去申请内存空间,大小固定,不利于后期扩展。所以产生了动态内存管理的这个概念。
2). 动态内存函数malloc() free()
1>. malloc()函数介绍
函数原型:
void* malloc(size_t size);
函数作用:
向内存申请一块连续可用的空间,并返回这块空间的首地址。申请失败则返回NULL。
说明:
这块空间是由程序员进行分配管理,所以在程序没有结束运行,系统都不会自动释放这块空间,所以就要额外注意这块空间的释放。
2>. free()函数介绍
函数原型:
void free(void* ptr);
函数作用:
用来释放动态开辟的内存。
说明:
free之后 虽然空间被释放了,但是指针依旧指向原来的内存空间,如果对指针做操作,仍然可以操作该空间,可能会导致程序崩溃。 一般在free内存空间后,要对 指针赋值为NULL,防止误操作。
3). 通过动态内存函数创建数组及二维数组示例
// 创建一维数组
int* ptr = (int*)malloc(num * sizeof(int));
// 判断申请内存空间是否成功
if(NULL == ptr)
{
exit(0);
}
// 初始化内存空间
for(int i = 0; i < num; i++)
{
ptr[i] = 0;
}
// 释放内存空间
free(ptr);
// 释放完后,赋值为NULL 防止误操作
ptr = NULL;
创建二维数组
// 创建一个字符串数组
// 动态分配一个数组,数组中的每个元素都是char*
// 相当于创建二维数组的 str[][] 第一个方括号
char** str = (char**)malloc(n * sizeof(char*));
// 判断是否申请成功
if(str == NULL)
{
exit(0);
}
// 对数组中元素再次进行内存空间的申请
// 相当于创建二维数组 str[][] 第二个括号
for(int i = 0; i < n; i++)
{
str[i] = (char*)malloc(len * sizeof(char));
}
// 初始化与二维数组操作相同
// 释放空间 需要分两次释放
// 1.先释放二维数组中每个元素的空间
for(int i = 0; i < n; i++)
{
free(str[i]);
str[i] = NULL;
}
// 2. 释放n个长度的str
if(str != NULL)
{
free(str);
str = NULL:
}
2. realloc()函数
函数原型:
void* realloc(void* ptr, size_t size);
函数作用:
可以调整已经申请的内存空间大小,并且会将原空间的数据移动到新空间。
参数列表:
*ptr: 要调整的内存地址
size: 调整之后的新大小
返回值:调整内存空间之后的空间起始地址。
realloc()函数的模拟实现:
void* my_realloc(void* memblock, size_t size)
{
// 1.申请新的内存空间
void* new_base = malloc(size);
if(new_base != NULL)
{
return -1;
}
// 2.拷贝数据
memcpy(new_base, memblock, size);
// 3.释放原来的内存空间
free(memblock);
// 4.返回新空间首地址
return new_base;
}
3. 常见的动态内存错误
- 对NULL指针的接引用操作
- 对动态开辟空间的越界访问
- 对非动态开辟内存使用free释放
- 使用free释放一块动态开辟内存的一部分
int *p = (int*)malloc(10);
p++; // p的起始位置发生了改变
free(p); // err
- 对同一块内存释放了多次
- 动态开辟内存忘记释放
4. 柔性数组
1). 定义
结构体中最后一个元素是未知大小的数组。
struct Test
{
int i;
int a[0]; // 柔性数组
};
2). 特点
- 结构体中的柔性数组成员前面必须只有有一个其他类型成员。
- sizeof计算结构体大小,不包含柔性数组
- 包含柔性数组成员的结构用malloc()函数进行内存动态分配,并且分配的内存大小应该大于结构体的大小,以适应柔性数组的预期大小。
3).使用
int i = 0;
Test *p = (Test*)malloc(sizeof(Test) + 100*sizeof(int));
p->i = 100;
// 柔性数组a获得了100个整形连续空间
for(int i = 0 ; i < 100; i++)
{
p->a[i] = i;
}
// 释放空间
free(p);
如果不采用柔性数组实现相同功能,释放内存空间需要释放先释放结构体内部申请的一维数组空间,在释放整个结构体空间。