超详细的C进阶教程!动态内存管理
Posted 东条希尔薇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了超详细的C进阶教程!动态内存管理相关的知识,希望对你有一定的参考价值。
作者的码云地址:https://gitee.com/dongtiao-xiewei
后续作者会更新力扣的每日一题系列,原代码会全部上传码云,推荐关注哦,笔芯~
还像更深入地了解c语言?快来订阅作者的c语言进阶专栏!作者承诺本系列不会TJ!预计更新:指针,字符串处理,内存管理,结构体,预处理等等
我们在以前的文章中提到,其实计算机的内存分为以下三个区
- 栈区:用于存放临时变量,形式参数
- 堆区:用于动态内存管理
- 静态区:用于存放静态变量,全局变量等
而我们今天要讨论的动态内存管理,则是在堆区上创建的
一般来说,堆区的空间比栈区要大,堆区大约有几个G的内存而栈区可能只有几百M
引例
为什么会存在动态内存分配?
比如,我们要实现这种变长数组
int n=0;
scanf("%d",&n);
int a[n]={0};
这个数组的长度在使用前我们是不知道的,所以用一个变量来代替
但是,这个代码并不一定在所有编译器上都能编译成功,所以导致了一个可移植性的问题
但用动态内存管理,就能解决变长数组的跨平台问题了
int n=0;
scanf("%d",&n);
int* arr=(int*)malloc(sizeof(int)*n);
这个代码可以在堆区开辟n个整型的空间
亦或者,比如力扣第一题
我们需要返回一个int*,也就是一个整型数组
但返回方式就只能先在堆上开辟空间,进行修改后再返回这一块空间起始位置的指针
因为,在函数内开辟的数字,出了函数是要销毁的,所以不能直接返回
所以,动态内存管理是C语言一个重要的部分
而要介绍这一章的内容,核心是以下的几个函数
注意,动态内存函数需要<stdlib.h>头文件!
动态内存函数介绍
malloc函数
函数有一个参数,代表需要开辟空间的大小,单位字节
这个函数的功能是在堆上开辟一块连续的空间,函数返回一个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;
}
输出结果
总结与提示
- 使用动态空间时一定要检查空间开辟是否成功
- 你最好不要越界访问,对程序没有什么好处
- 不要去尝试对非动态开辟内存执行free函数
- free这块空间时,严禁修改指向这块空间的指针值
以上是关于超详细的C进阶教程!动态内存管理的主要内容,如果未能解决你的问题,请参考以下文章