本篇文章计划用最简单的方式向大家介绍C语言动态内存管理这一问题
如果各位看官姥爷们觉得有用的话,不妨动动你们手指,点赞、评论、收藏哦!
目录
1.为什么需要动态内存分配
我们常见的内存开辟方式有:
int a = 20;//在栈空间上开辟四个字节
char arr[10] = { 0 };//在栈空间上开辟10个字节的连续空间
上述内存开辟方式有两个特点:
1. 空间开辟大小是固定的。2. 数组必须指定数组的长度,以获取所需内存。
但是我们对于空间的需求,不仅仅是上述的情况。有时候我们需要根据情况来决定开辟空间的大小
此时动态内存的作用就凸显出来了
2.动态内存的介绍
2.1malloc和free
void* malloc(size_t size);
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
void free(void* ptr);
C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收
话不多说,直接上代码
int main()
{
int arr[40] = {0};
int* prt = (int*)malloc(40);//申请空间
//检查
if (prt == NULL)
{
perror("malloc");//检查错误的函数,要使用双引号,检查的是开辟空间的malloc
return 1;
}
//初始化
int i = 0;
for (i = 0; i < 10; i++)
{
*(prt + 1) = i;
}
//释放空间
free(prt);//这里释放的是地址,因此不需要解引用
prt = NULL;
return 0;
}
2.2calloc
C语言还提供了一个函数叫 calloc , calloc 函数也用来动态内存分配,其具体使用我们结合下面一个函数来讲解
- 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0
void* calloc(size_t num, size_t size);
2.3realloc
- realloc函数的出现让动态内存管理更加灵活。
- 当我们发现过去申请的空间太小或太大,那为了合理的使用内存,我们可以使用realloc 函数实现对动态开辟内存大小的调整。
void* realloc(void* ptr, size_t size);
话不多说,让我们一起来看一下calloc和realloc代码的实现吧
int main()
{
//申请空间
//calloc需要两个参数(元素、每个元素类型的大小)
//且在申请之初就会初始化空间为0
int* ptr = (int*)calloc(10, sizeof(int));//ptr必须是指针
//检查
if (ptr == NULL)
{
perror("calloc");//打印错误
return 1;
}
//打印
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", *(ptr + i));
}
//释放空间
//free(calloc);
//假设空间不够,需要扩容20个元素
//原内存空间不够会重新寻找一块空间,将原有内存剪切到新的大空间上,并且把原空间释放
int *p = (int*)realloc(ptr, 80);//20个整形需要80个字节
if (*p != NULL)//防止内存不够,返回空指针
{
ptr = p;
}
//扩容成功
free(ptr);
ptr = NULL;
return 0;
}
3.常见的动态内存使用错误
3.1对空指针的解引用操作
即没有判空,在malloc等函数申请空间是有可能会申请到空指针;
解决方法:判空
3.2对动态空间进行越界访问
解决方法:弄清楚动态内存的边界
for (i = 0; i <= 10; i++)//原申请空间<10,超过10会出现越界访问
{
printf("%d ", *(ptr + i));
}
3.3 对非动态开辟空间使用free
必须在动态开辟空间的起始位置进行释放,否则可能会造成内存泄露(只申请,不归还)
3.4使用free释放动态内存的一部分
3.5对同一静态内存的多次释放
3.6忘记释放空间
4.经典笔试题练手
4.1练习一
void GetMemory(char* p) //这里的指针p在函数结束之后就销毁了,没有将地址返回到Test函数中
{
p = (char*)malloc(100);
}
void Test(void) {
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
4.2练习二
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();//虽然str获取到了字符串的地址,但是由于上函数的销毁,原空间也不存在了,无法在进行访问
printf(str);
}
4.3练习三
void GetMemory(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test(void) {
char* str = NULL;
GetMemory(&str, 100);//如果不取地址将无妨修改str
strcpy(str, "hello");
printf(str);
//忘记释放空间
//free(str);
//str = NULL;
}
4.4练习四
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
//str = NULL;//可以通过设置空指针避免此类问题
if (str != NULL)
{
strcpy(str, "world");//free已经将空间还给操作系统了,这里的修改是非法修改
printf(str);
}
}
5.结语
看到这里,相信老铁们对动态内存管理的知识已经有了基本的了解。
我是计算机海洋的新进船长Captain_ldx,如果我的文章能对您有帮助的话,麻烦各位观众姥爷们点赞、收藏、关注我吧!如果你对我的文章有任何问题或者意见,欢迎在评论区给我留言。后期更多知识点将持续更新......