C语言进阶系列|超详细的C进阶教程!(五)动态内存管理

作者的码云地址:https://gitee.com/dongtiao-xiewei
后续作者会更新力扣的每日一题系列,原代码会全部上传码云,推荐关注哦,笔芯~
还像更深入地了解c语言?快来订阅作者的c语言进阶专栏!作者承诺本系列不会TJ!预计更新:指针,字符串处理,内存管理,结构体,预处理等等
我们在以前的文章中提到,其实计算机的内存分为以下三个区
  1. 栈区:用于存放临时变量,形式参数
  2. 堆区:用于动态内存管理
  3. 静态区:用于存放静态变量,全局变量等
而我们今天要讨论的动态内存管理,则是在堆区上创建的
一般来说,堆区的空间比栈区要大,堆区大约有几个G的内存而栈区可能只有几百M

目录
  • 引例
  • 动态内存函数介绍
    • malloc函数
    • calloc函数
    • free函数
    • realloc函数
  • 总结与提示

引例 为什么会存在动态内存分配?
比如,我们要实现这种变长数组
int n=0; scanf("%d",&n); int a[n]={ 0};

这个数组的长度在使用前我们是不知道的,所以用一个变量来代替
但是,这个代码并不一定在所有编译器上都能编译成功,所以导致了一个可移植性的问题
但用动态内存管理,就能解决变长数组的跨平台问题了
int n=0; scanf("%d",&n); int* arr=(int*)malloc(sizeof(int)*n);

这个代码可以在堆区开辟n个整型的空间
亦或者,比如力扣第一题
C语言进阶系列|超详细的C进阶教程!(五)动态内存管理
文章图片

我们需要返回一个int*,也就是一个整型数组
但返回方式就只能先在堆上开辟空间,进行修改后再返回这一块空间起始位置的指针
因为,在函数内开辟的数字,出了函数是要销毁的,所以不能直接返回
所以,动态内存管理是C语言一个重要的部分
而要介绍这一章的内容,核心是以下的几个函数
注意,动态内存函数需要头文件!
动态内存函数介绍 malloc函数 函数有一个参数,代表需要开辟空间的大小,单位字节
【C语言进阶系列|超详细的C进阶教程!(五)动态内存管理】这个函数的功能是在堆上开辟一块连续的空间,函数返回一个void指针,指向这块空间的起始位置
int* arr = sizeof(20); 开辟20字节的空间,由int接受

但你需要注意:这个函数的返回类型是void*类型,万能接受指针,使用前最好强制类型转换一下,与数组类型匹配
int* arr = (int*)sizeof(20);

如果此函数开辟失败,则返回一个NULL指针
所以,在使用空间前,一定要检查有效性
int main() { int* arr = (int*)malloc(20); if (!arr) {printf("fail\n"); exit(-1); } else {//操作 } return 0; }

有什么情况会返回失败呢?
当然有,你开辟的空间过大,将会开辟失败!
calloc函数 这个函数有两个参数,第一个参数代表开辟的元素个数,第二个参数代表每个元素占的字节数
另外,这个函数会自动将这块空间初始化为0,但malloc不会
以下两个数组是等价的
int arr[10] = { 0 }; int* arr1 = (int*)calloc(10, sizeof(int));

free函数 这个函数的参数是一个地址,可以将指向的这块动态管理的空间释放掉
使用示例:
int main() { int* arr = (int*)malloc(20*sizeof(int)); if (!arr) {printf("fail\n"); exit(-1); } else {//操作 } return 0; } free(arr); arr=NULL; //这步有必要吗

最后一句虽然可以去掉,但这个语句却非常重要
因为将空间释放掉了,这块空间就还给操作系统了就不属于我们了!这个指针也成了俗话说的野指针
所以,最后一句可以防止野指针问题
我们在编程中,为了防止内存泄露在此空间使用完成后,必须及时释放掉!
realloc函数 这个函数两个参数,第一个为一个数组,第二个是一个大小
这个函数的功能是将原数组调整到指定大小!
使用示例
注意:需要一个中间变量来交换**(会自动将原数组数据拷贝),同样需要检查有效性**
int main() { int* arr = sizeof(20); if (!arr) {printf("fail\n"); exit(-1); } int* tmp = realloc(arr, 100); if (!tmp) {printf("fail\n"); exit(-1); } else {arr = tmp; //操作 } return 0; }

完整的动态空间使用示例
int main() { int* arr = (int*)malloc(sizeof(int) * 10); if (!arr) {printf("fail\n"); exit(-1); } for (int i = 0; i < 10; i++) {arr[i] = i; printf("%d ", arr[i]); } int* tmp = (int*)realloc(arr, 20 * sizeof(int)); if (!tmp) {printf("fail\n"); exit(-1); } arr=tmp; for (int i = 11; i < 20; i++) {arr[i] = i; printf("%d ", arr[i]); } free(arr); arr = NULL; tmp = NULL; return 0; }

输出结果
C语言进阶系列|超详细的C进阶教程!(五)动态内存管理
文章图片

总结与提示
  1. 使用动态空间时一定要检查空间开辟是否成功
  2. 你最好不要越界访问,对程序没有什么好处
  3. 不要去尝试对非动态开辟内存执行free函数
  4. free这块空间时,严禁修改指向这块空间的指针值

    推荐阅读