C语言|空间用多少我说了算! C语言动态内存!
空间大小我说了算--动态内存
- 为什么存在内存分配
- malloc 开辟空间 free 释放空间
-
- malloc
- free
- calloc 开辟空间
- realloc 管理内存
-
- realloc 调整内存的两种情况
-
- 情况1:原有空间之后有足够大的空间
- 原有空间之后没有足够大的空间
- realloc 使用代码示例
为什么存在内存分配 我们之前学的内存分配,都是直接开辟内存。但是这样有一个问题:我们开辟的内存是大了还是小了,会不会浪费,会不会不够用。有的程序只有在运行的时候才知道要用多少空间。所以为了解决这样的问题,我们就有了内存的动态开辟。
动态内存都是在堆区上面的,外面操作动态内存的,malloc free calloc realloc 也都是对堆区的内存进行操作。
malloc 开辟空间 free 释放空间 malloc malloc 是C语言提供的动态内存开辟函数。
viod* malloc(size_t size);
malloc 申请的是连续的空间。如果开辟成功,那么返回的就是开辟的内存的起始地址。如果开辟失败,就返回 NULL 。返回值的类型是 void* 因为 malloc 不知道开辟的内存是什么类型。所以我们使用的时候,可以强制类型转换一下。转换为我们要使用的类型。例如:我们开辟整型内存。
int* p = (int*)malloc(10*sizeof(int));
free free 就是对开辟的堆区空间进行释放。每次 free 释放内存之后,一定要把指针变量置为 NULL 防止出现野指针。用法如下:
int* p = (int*)malloc(10*sizeof(int));
free(p);
p = NULL;
使用一个变量来开辟空间,这里使用一个变量 num 来开辟一段动态空间:
int main()
{ int num = 0;
scanf("%d", &num);
int* ptr = (int*)malloc(num * sizeof(int));
if (ptr != NULL)
{int i = 0;
for (i = 0;
i < num;
i++)
{*(ptr + i) = i + 1;
}
for (i = 0;
i < num;
i++)
{printf("%d ", *(ptr + i));
}
}
free(ptr);
ptr = NULL;
return 0;
}
文章图片
这里就是通过输入一个数 num 然后开辟相应的内存空间。并且赋值为 1 - 10 。
calloc 开辟空间 C语言也提供了另外一个开辟空间的函数,calloc 与 malloc 不同的是,calloc 开辟空间之后,在返回空间的起始地址之前,把所有空间全部赋值为 0 。示例:
//C语言文档给的代码
void* calloc (void* ptr, size_t size);
int main()
{ int* p = (int*)calloc(10, sizeof(int));
if (NULL != p)
{//使用空间
}
free(p);
p = NULL;
return 0;
}
文章图片
文章图片
由第二张图片就可以看到,p 所指向的空间,全部被置为了 0 。如果我们对申请的内存有初始化的需求,就可以使用 calloc 来进行初始化。
realloc 管理内存 有时候我们会发现申请的内存大了或者小了,所以就用到 realloc 来对内存大小进行灵活的调整。如果 realloc 调整内存失败后,也会返回空指针。C语言给的函数模型是这样:
void* realloc (void* ptr, size_t size);
ptr 是要调整的内存地址。
size 是要调整的大小。
返回值是调整大小之后的内存起始位置。
realloc 调整内存的两种情况 情况1:原有空间之后有足够大的空间
【C语言|空间用多少我说了算! C语言动态内存!】当原来的空间后面有足够大的空间的话,就连着原有空间继续开辟,就是下面图片这样的情况。就是原有内存之后直接追加空间,原来空间的数据不发生变化,并且返回值的地址还是原来的地址。
文章图片
原有空间之后没有足够大的空间
当原来空间的后面没有足够大的空间的话,其扩展的方法就是:再找一块空间,可以放得下原有的空间的内容和新开辟的空间,并且返回新的内存地址。不过在传回新的地址之前。会把原来的那段空间 free 掉。不能用原来的指针去接收返回值,因为如果开辟失败,那么原来的指针也变成 NULL 了。就是下图这样:
文章图片
realloc 使用代码示例
int main()
{ int* p = (int*)calloc(10, sizeof(int));
//空间不够 增加到 20个 int
int* ptr = (int*)realloc(p, 20 * sizeof(int));
if (ptr != NULL)
{p = ptr;
}
else
{//ptr是空指针 返回-1
return -1;
}
//增容成功
for (int i = 10;
i < 20;
i++)
{*(ptr + i) = i;
}
for (int i = 0;
i < 20;
i++)
{printf("%d ", *(ptr + i));
}
free(ptr);
ptr = NULL;
free(p);
p = NULL;
return 0;
}
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- JS中的各种宽高度定义及其应用
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- 涉毒患者(新诗)
- 参保人员因患病来不及到指定的医疗机构就医,能否报销医疗费用()
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。