文章目录
为什么存在动态内存管理?
#include <stdio.h>
int main()
{
int arr[20] = { 0 };
return 0;
}
上述代码中的arr数组已经被我们创立,但这样设计代码可能会有一定的缺陷,如果当我们所需要用的数据超过 arr数组的长度时,会形成数组越界,而造成语法出错。这时,动态内存分配管理便由此而出。
动态内存管理相关函数
malloc 和 free
C语言为我们提供了相应的动态内存管理函数。首先我们将要了解的是开辟动态内存空间的 malloc 和释放动态内存空间的 free。
malloc
函数原型:void malloc (size_t size);
size_t size 表示malloc所创建的空间是我们自己决定和创建的,其大小为字节。如size为0时,这是标准没有定义的,结果取决于编译器自身。
void* 表示可以返回任意类型的指针,使用我们在使用malloc时,一定要强制类型转换成我们自己所需要的
注:
当我们使用malloc向内存开辟空间时, malloc会有两种情况:
(1)当malloc开辟成功时,返回一个指向开辟好空间的指针
(2)当malloc开辟失败是,返回一个NULL指针,所以在使用malloc开辟空间后,一定要判断malloc是否开辟成功。
free
C语言同时也提供个释放和回收动态内存的函数:free
函数原型: void free (void ptr);
ptr 表示了在使用free函数时,需要我们将动态空间的首地址传输给free,
同时free并不需要返回值
注:
在使用完free后, 一定要将 ptr 赋成NULL。
以代码举例
#include <stdio.h>
//使用malloc和free时需要引的头文件
#include <stdlib.h>
int main()
{
//代码1
int num = 0;
scanf("%d", &num);
int arr[num] = { 0 };//C99中存在
//代码2
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
{
return;//如果ptr开辟失败,程序直接结束
}
free(ptr);
ptr = NULL;//必须赋为NULL
return 0;
}
calloc
C语言除了malloc可以申请动态空间外,还有calloc函数同样可以申请
函数原型:void calloc (size_t num, size_t size);*
(1)calloc是指开辟 num 个 大小为 size 的空间,同时将每个字节赋为 0;
(2)malloc 和 calloc 的区别在于 calloc会将每个字节初始化为 0;
代码举例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)calloc(10, sizeof(int));
if (p == NULL)
{
return;
}
//释放
free(p);
p = NULL;
return 0;
}
由上图可以看出,calloc开辟空间时会把每个字节都赋为 0。
对于在使用 malloc 和 calloc 时,我们可以根据实际情况选择使用。
不需要初始化时, 使用malloc
需要初始化为全0时,就使用calloc
realloc
realloc 的出现使得动态内存管理更加灵活。
当我们发现 malloc或者calloc开辟的空间小或者大时,可以使用realloc 进行空间调整。
函数原型:void realloc (void ptr, size_t size);
ptr 是要调整的内存地址
size 是调整之后的新大小
返回值是调整之后的内存起始地址
realloc 会将原有的数据拷贝到新分配的空间里面去
注: realloc重新开辟空间时,会有两种情况
- 情况1: 原有空间之后有足够大的空间
- 情况2:原有空间之后的空间不足
情况一:当后续空间足够大时,直接扩展到后续空间,原有数据也不改变
情况二:当后续空间不足够时,拓展方法为:将原有数据拷贝,再在空间中找到内存空间足够大的连续空间使用,然后返回一个新的内存地址。
代码举例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)malloc(10 * sizeof(int));
//开辟失败直接返回
if (p == NULL)
{
return;
}
int* ptr = (int*)realloc(p, 100);
//如果开辟失败
if (ptr == NULL)
{
return;
}
p = ptr;//我们需要将新分配的地址赋给原地址
//释放
free(p);
p = NULL;
return 0;
}
动态内存管理容易存在的错误
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main()
{
//INT_MAX的值为 2147483647
int* p = (int*)malloc(INT_MAX);
//没有进行判断p是否开辟成功
*p = 20;
free(p);
p = NULL;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)malloc(20);//20个字节
if (p == NULL)
{
return;
}
int i = 0;
for (i = 0; i < 10; i++)//当i>=5时就会造成越界访问
{
*(p + i) = i;
}
free(p);
p = NULL;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
int p = 0;
int* i = &p;
//错误释放
free(i);
p = NULL;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)malloc(20);//20个字节
if (p == NULL)
{
return;
}
free(p);
free(p);//重复释放
p = NULL;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)malloc(20);//20个字节
if (p == NULL)
{
return;
}
int i = 0;
for (i = 0; i < 10; i++)//当i>=5时就会造成越界访问
{
p += i;//改变了动态开辟的初始位置
}
free(p);
p = NULL;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void test()
{
int* p = (int*)malloc(10 * sizeof(int));
if (p != NULL)
{
*p = 20;
}
}
int main()
{
test();
//没有用free释放,会造成空间泄漏
return 0;
}
注:动态开辟后的空间一定要释放,并且要释放正确
谢谢大家的阅读,让我们一起努力变强吧!