
🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言 🔥专栏:《C语言入门知识点》、《C语言底层》、《精通C语言》、《C语言编程实战》 💪格言:做好你自己,你才能吸引更多人,并与他们共赢,这才是你最好的成长方式。
我们提法C语言或者说各种编程语言,其实就是与他们对内存的处理打交道,今天依旧是围绕内存来做一些文章:动态内存管理。包括接下来的几篇也都是关于动态内存管理的文章,今天我们先来了解一下四个有关动态内存管理的函数吧,记好笔记出发喽~
我个人认为,你学一个东西,你一定要带有目的性的学,就像是你高中时,学习很大程度上本来就是为了高考服务的,而到了大学乃至其他阶段,你学习更要有一个目标,漫无目的的学是行不通的,你连学一个知识的目的是什么都不知道,你怎么能学好它
那我们就开始,到底什么是动态内存管理,以及为什么需要动态内存管理
我们平时开辟内存空间是怎么开的呢?我们知道两种方式:
int i = 0;
int arri[30] = { 0 };这两种方式一种是直接以整型为单位开辟四个字节的空间,另一种是以数组为单位来开辟想要的空间大小 但是这两种方式,他们对空间的开辟都是固定的,对于数组,就有三种情况: ① 我们现在需要存大于30个整数,那么上面的空间显然就不够通用了 ②刚好够用 ③需要存小于30个整数,上面的空间就多出来了,会被浪费掉
这种时候第二种当然是最好的,但是我们很难保证每次都是第二种情况,这个时候就需要动态内存管理了
先直观的来说
malloc函数是用来开辟空间的,free函数是用来释放空间的malloc中的m是memory“存储 ”的意思,alloc是allocate“开辟 ”的意思free是“自由 ”的意思 下面我们看一下他们在C语言标准库中的描述
malloc

free

可以看到他们都是在头文件
<stdlib.h>中的函数 下面是他们的作用,意为"开辟内存空间"和“释放内存空间”
那我们来看看具体怎么用吧:
标准形式:
void* malloc(size_t size);返回结果
size为0,会根据编译器不同产生不同的结果演示:
//x64环境下
//void* malloc(size_t size)
int main()
{
int* p = (int*)malloc(10 * sizeof(int));
int* ptr = (int*)malloc(INT_MAX);
if (p != NULL)
{
printf("yes\n");
}
if (ptr != NULL)
{
printf("yes\n");
}
printf("p申请大小: %zu\n", 10 * sizeof(int));
printf("ptr申请大小: %zu\n", (size_t)INT_MAX * sizeof(int)); // 观察是否溢出
return 0;
}运行结果:
yes
yes
p申请大小: 40
ptr申请大小: 8589934588//x86环境下
//void* malloc(size_t size)
int main()
{
int* p = (int*)malloc(10 * sizeof(int));
int* ptr = (int*)malloc(INT_MAX);
if (p != NULL)
{
printf("yes\n");
}
if (ptr != NULL)
{
printf("yes\n");
}
return 0;
}运行结果:
yes为什么两种情况下会不一样呢?
malloc函数必然申请不到足够的连续的内存空间。标准形式:
void free(void* ptr)返回结果:
ptr不是动态内存开辟的指针,那free的行为是未被定义的ptr是一个NULL,那free将没有行为,什么都不做演示:
//void free(void* ptr)
int main()
{
int* ptr = (int*)malloc(10 * sizeof(int));//这里的10可以用过变量代替
if (ptr != NULL)
{
int i = 0;
for (i = 0; i < 10; i++)
{
*(ptr + i) = 0;
}
}
free(ptr);
ptr = NULL;
return 0;
}这就是一个完整的
free函数搭配malloc函数的代码free是释放内存空间的,但是后来一定得使空间置空,不然还是可以找到,导致麻烦
主要有三个麻烦之处
free(ptr);
// 未执行 ptr = NULL;
*ptr = 10; // 错误:向已释放的内存写入数据,属于访问非法内存free(ptr);
// 未执行 ptr = NULL;
free(ptr); // 错误:重复释放同一内存块free(ptr);
// 未执行 ptr = NULL;
if (ptr != NULL) { // 错误:野指针非空,判断为“有效”
*ptr = 20; // 实际访问已释放内存
}同malloc函数一样,他们两个函数都是用来开辟内存空间的
calloc函数中c是clear“清零 ”的意思,realloc函数是reallocate“重新分配 ”的意思 依旧是看从语言标准库中的描述:
calloc

realloc

依旧是头文件
<stdio.h>中的函数calloc与malloc效果唯一不同的一点就是他会把开辟的内存空间全部初始化成0realloc则是对已有的空间进行重开辟
这里就直接演示一下:
int main()
{
int* ptr = (int*)calloc(10, sizeof(int));
int i = 0;
for (i = 0;i < 10; i++)
{
printf("%d %d\n", *(ptr + i),i+1);
}
free(ptr);
ptr = NULL;
return 0;
}运行结果:
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9
0 10可以看到开辟出的内存储存的值全部都是0
realloc函数的出现让动态内存管理更加灵活。 有时会我们发现过去申请的空间太⼩了,有时候我们⼜会觉得申请的空间过⼤了,那为了合理的使⽤内存,我们⼀定会对内存的⼤⼩做灵活的调整。 那realloc函数就可以做到对动态开辟内存⼤⼩的调整。
void* realloc (void* ptr, size_t size);
ptr是指向要调整的地址的指针size是调整后的空间大小 返回值为指向调整后的地址的指针但是
realloc实际上会有两种情况:

这就导致会有不一样的结果:
使用案例:
//代码一,ptr是原开辟地址
ptr = (int*)realloc(ptr, 1000);//代码二
int* p = NULL;
p = realloc(ptr, 1000);
if (p != NULL)
{
ptr = p;
}这两种代码是对于原地址的两种处理结果 需要注意的是,第一种一旦发生空间不够位置改变,原来的数据就很难再找回来了 所以正确的应该是第二种