动态内存分配在初级C语言中是一个极其重要的章节,不管是现在还是将来,学好动态内存分配的我们将会终生受益。本篇文章较适合于初学者阅读,在初期学到的内容基本上都会在这里呈现。本篇博客从写入到结束历史5小时,觉得这篇文章总结的较为详细的话别忘了收藏与关注哦(我愿称之为舔狗级别讲解),后续我将更新更深一层的动态内存分配。
在学到这知识点之前的我们是否会这样的问题,在之前我们学的一般的变量都要先确定大小,但在使用的时候往往不太如人意,就拿排序来说吧,如果我们所要排序的数字小于编译前确定的大小,是否会造成内存浪费?若大于编译前确定的大小,那我们在编译前分配的内存就显得不够用了。那有没有什么方法能够解决这个问题呢?答案当然是运用动态内存分配!
目录
内存的四块区域
malloc()和free()
calloc()
malloc()和calloc()的区别
realloc()
动态内存分配那点坑
内存的四块区域 在进入正题之前我想先描述一下内存的四块存储区域:栈,堆,静态(存储)区,代码区。
栈区->局部变量及函数的形式参数;
堆区->动态内存分配;
静态区->全局变量及静态变量;
#include
int b = 0;
//全局变量
int main()
{
int a = 0;
//局部变量
}
比如说int a 是局部变量,在栈区,在前面加上static以后则变成静态变量,在静态区。
栈区 | 部变量及函数的形式参数 |
堆区 | 动态内存分配 |
静态区 | 全局变量及静态变量 static int a=0 |
malloc()和free() malloc的原型void* malloc(size_t size)free的原型void free(void * memblock)
动态内存是如何开辟与释放的呢?malloc函数可以在堆上申开辟一个我们想要的大小的空间;free函数能在当动态申请的空间不再使用的时候释放还给操作系统。注意:malloc()和free()是成对存在的,此点在下文会描述到。
#include
#include
#include
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
//该函数返回一个指向错误字符串的指针,该错误字符串描述了错误 errno
}
else
{
int i = 0;
for (i = 0;
i < 10;
i++)
{
*(p + i) = i;
}
for (i = 0;
i < 10;
i++)
{
printf("%d ", *(p+i));
}
}
free(p);
//将不再使用的空间返还给操作系统,若缺少此条件则会造成内存泄漏。
p = NULL;
return 0;
}
如上我们想内存申请了40个字节大小的空间并返回指向这块空间的指针。在使用malloc函数后一定要记得检验malloc的返回值,如果开辟成功,则返回一个指向开辟好空间的指针;如果开辟失败,则返回一个NULL指针。返回值的类型是void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。像上面这个例子则是将开辟空间的类型设为int*。
calloc() calloc函数原型void* calloc(size_t num,size_t size)
其中第一个参数size_t num是想要开辟的元素个数,第二个参数size_t size是元素的大小。
#include
#include
int main()
{
int* pc = (int*)calloc(10, sizeof(int));
//calloc()与malloc()的使用并没有什么不同,不同之处在于------>下面给你揭晓~
if (pc == NULL)
{
printf("%s\n", strerror(errno));
}
int i = 0;
for (i = 0;
i < 10;
i++)
{
*(pc + i) = i;
}
for (i = 0;
i < 10;
i++)
{
printf("%d ", *(pc + i));
}
free(pc);
pc = NULL;
return 0;
}
malloc()和calloc()的区别 malloc函数生成的是xx个字节大小未被初始化的内存空间,而calloc函数生成的是xx个字节已被初始化为0的空间。话不多说,上图上代码!
malloc()如下:
#include
#include
int main()
{
int* pc;
pc = (int*)malloc(sizeof(int*)*10);
printf("%p\n", pc);
}

文章图片
calloc()如下:
#include
#include
int main()
{
int* pc;
pc = (int*)calloc(10,sizeof(int));
printf("%p\n", pc);
}

文章图片
仔细观察内存地址会发现,malloc()与calloc()开辟的内存空间有 有无初始化 之别。可以自己去编译器那里写段代码按f10,打开监视与内存自己去调试一下你就会深信不疑啦,希望看到这的你能自己去调试一下,眼动不如手动,手动如下,上图:

文章图片
realloc() realloc函数模型void* realloc(void* ptr,size_t size)
其中第一个参数是指向某个动态内存的指针,第二个参数是想要加入的空间的大小。
话不多说,上代码:
#include
#include
#include
int main()
{
int* p = (int*)malloc(20);
if (p == NULL)
{
printf("%s\n", strerror(errno));
}
else
{
int i = 0;
for (i = 0;
i < 5;
i++)
{
*(p + i) = i;
}
}
int* ptr = (int*)realloc(p, INT_MAX);
if (ptr != NULL)
{
p = ptr;
}
int i = 0;
for (i = 5;
i < 10;
i++)
{
*(p + i) = i;
}
for (i = 0;
i < 10;
i++)
{
printf("%d ", *(p + i));
}
free(p);
p = NULL;
return 0;
}
其中,INT_MAX含义如→

文章图片
;
读者可以自己写代码去实现一下,若没有realloc()是无法实现0 1 2 3 4 5 6 7 8 9的,这就是追加空间的妙用。但realloc()追加空间的道路并不是一帆风顺的。
realloc()使用注意事项:
如果p指向的空间之后有足够的内存空间可以追加,则直接追加,后返回p |
如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存区域开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间 |
得用一个新的变量来接受realloc函数的返回值 |
接下来我要列举一些小白经常会犯的错误,希望看到这篇文章的你能避开这些坑。
动态内存分配那点坑 1
1.对NULL进行解引用操作; |
2.对动态开辟内存的越界访问; |
3.对非动态开辟内存使用free释放; |
4.使用free释放动态开辟内存的一部分; |
5.对同一块动态内存的多次释放; |
6动态开辟内存忘记释放(内存泄漏)。 |
接下来大部分代码段是为了讲解那些坑,并不能实现!!!
1.对NULL进行解引用操作:当要开辟的空间非常非常大的时候就可能会出现这个情况
int*p=(int*)malloc(95845635894)//太大啦所以error
2.对动态开辟内存的越界访问:用malloc()开辟了xx个字节大小的空间,妄想把xx+N*(N*为大于0的数)大小的东西塞到里面去
#include
#include
int main()
{
int* p = (int*)malloc(16);
if (p == NULL)
{
printf("%s\n", strerror(errno));
}
else
{
int i = 0;
for (i = 0;
i < 5;
i++)//16<20
{
*(p + i) = i;
}
}
free(p);
p = NULL;
return 0;
}
3.对非动态开辟内存使用free释放:简单来说就是栈区的不归堆区管
{
int a = 10;
int* pc = &a;
free(pc);
pc = NULL;
}
error!
4.使用free释放动态开辟内存的一部分:简单来说就是,月下的你不复当年模样(循环的时候发现她已经不再是原来的那个她,因为她已经不在原地了),上代码:
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
}
int i = 0;
for (i = 0;
i < 10;
i++)
{
*p++ = i;
//这里是问题所在
}
return 0;
}
5.对同一块动态内存的多次释放:多次运用free()
int main()
{
int* p = (int*)malloc(20);
if (p == NULL)
{ }
free(p);
//1个
p = NULL;
free(p);
//2个
}
6.动态开辟内存忘记释放(内存泄漏):末尾没有free()你的电脑就很不free了,要意识到这是个很严重的问题!!!
int main()
{
int* p = (int*)malloc(20);
if (p == NULL)
{ }
else
{
int i = 0;
for (i = 0;
i <5;
i++)
{
*(p + i) = i;
}
}
return 0;
}
不free掉,后果很严重!
【易懂|动态内存分配浅论】感谢能阅读到这的你,如果觉得这篇文章对你理解动态内存分配有帮助的话,请留下你的收藏与点赞哦。
推荐阅读
- 易懂|C语言小游戏(一)----猜数游戏
- 笔记|C语言扫雷简化版(b站鹏哥)
- 第十二届蓝桥杯大赛软件赛省赛B组题解
- 数据结构之究竟什么是树
- 数据结构|遗落在时光里的静态链表(线性表的静态存储)---C语言版
- 数据结构|栈(操作受限的线性表)---C语言版
- c语言|单链表(线性表的链式存储)---C语言版
- c语言|垃圾回收GC经典算法
- 单片机|单片机学会了有出路吗(学单片机有什么用?)