【笔记】C语言的堆内存管理

前言

C语言的堆内存管理

引入头文件

1
#include <stdlib.h>

作用域

1
2
3
4
5
6
7
int a = 0; // 文件作用域
int main() {
int a = 0; // 函数作用域
{
int a = 0; // 代码块作用域
}
}

变量的种类

自动变量

  • 代码块内部定义的都是自动变量,只不过平常我们会省略auto关键字
1
2
3
{
auto int a = 0;
}

寄存器变量

1
register int a = 0;

静态变量

  • 静态变量放在代码块内或代码块外都可以
  • 静态变量只初始化一次,在程序加载到内存的时候就创建,直到程序运行结束才销毁
1
statis int a = 0;

全局变量和全局函数

  • 全局变量全局函数可以跨文件使用
  • 静态全局变量静态全局函数只能在定义它的文件内使用
a.c
1
2
3
4
5
6
7
8
// 定义一个全局变量
int a = 0;

// 定义一个全局函数
int b()
{
...
}
b.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 声明全局变量
extern int a;

// 声明全局函数
extern int b();

int main()
{
// 使用变量
a = 1;

// 调用函数
b();

return 0;
}

在堆中开辟一块空间

  • 一个程序的栈大小是有限的,如果一个数组特别大时,会导致栈溢出,所以不要在栈里面定义太大的数组,此时可以使用堆来存数据
  • 如果一个数组的长度不能确定的时候,适合用堆而不是用栈存储数据

<num>:空间大小,单位字节

1
数据类型 *变量名 = malloc(<num>);

自动变量

  • 如果存储为自动变量,在手动释放后仍然可以使用,但是释放后再次使用时,是一个新的堆空间,而且使用完仍然需要手动释放。释放的不是变量,而是指针指向的堆内的空间
1
auto 数据类型 *变量名 = malloc(<num>);

释放

  • 在堆中开辟的空间不会自动释放,需要手动释放
1
free(变量名);

在堆中开辟多块空间

  • malloc只负责开辟空间,所以需要自己使用memset来清空数据

<num> * sizeof(int):一共开辟的空间大小

1
int *变量名 = malloc(<num> * sizeof(int));
  • calloc不仅负责开辟空间,还会进行数据的初始化

<num>:开辟的空间个数
sizeof(int):每一块空间的大小

1
int *变量名 = calloc(<num>, sizeof(int));

重新分配开辟的空间

  • 使用malloc或calloc开辟的空间需要调整时,可以使用realloc
  • realloc开辟的空间也需要手动清除数据

变量名:想要修改空间的变量(返回的变量可以不相同,但通常设置为相同,因为旧的变量不需要自己维护)

1
变量名 = realloc(变量名, 新指定的内存大小);

最小堆内存单位

  • Windows堆内存最小页为4k
  • 所以如果从操作系统开辟1k空间,实际上操作系统会给4k空间,而再要时候,就不会再给空间,直到4k满了,再要1k空间时,操作系统再给4k空间
  • 优点是操作系统效率更高,缺点是会浪费内存

完成