精通C语言(4.四种动态内存有关函数)
🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言
🔥专栏:《C语言入门知识点》、《C语言底层》、《精通C语言》、《C语言编程实战》
💪格言:做好你自己,你才能吸引更多人,并与他们共赢,这才是你最好的成长方式。
前言:
我们提法C语言或者说各种编程语言,其实就是与他们对内存的处理打交道,今天依旧是围绕内存来做一些文章:动态内存管理。包括接下来的几篇也都是关于动态内存管理的文章,今天我们先来了解一下四个有关动态内存管理的函数吧,记好笔记出发喽~
文章目录
- 前言:
- 正文:
- 1.为什么要有动态内存管理
- 2. malloc函数和free函数
- 2.1 malloc函数
- 2.2 free函数
- 3. calloc函数和realloc函数
- 3.1 calloc函数
- 3.2 realloc函数
正文:
1.为什么要有动态内存管理
我个人认为,你学一个东西,你一定要带有目的性的学,就像是你高中时,学习很大程度上本来就是为了高考服务的,而到了大学乃至其他阶段,你学习更要有一个目标,漫无目的的学是行不通的,你连学一个知识的目的是什么都不知道,你怎么能学好它
那我们就开始,到底什么是动态内存管理,以及为什么需要动态内存管理
我们平时开辟内存空间是怎么开的呢?我们知道两种方式:
int i = 0;
int arri[30] = { 0 };
这两种方式一种是直接以整型为单位开辟四个字节的空间,另一种是以数组为单位来开辟想要的空间大小
但是这两种方式,他们对空间的开辟都是固定的,对于数组,就有三种情况:
① 我们现在需要存大于30个整数,那么上面的空间显然就不够通用了
②刚好够用
③需要存小于30个整数,上面的空间就多出来了,会被浪费掉
这种时候第二种当然是最好的,但是我们很难保证每次都是第二种情况,这个时候就需要动态内存管理了
2. malloc函数和free函数
先直观的来说
malloc
函数是用来开辟空间的,free
函数是用来释放空间的
malloc
中的m
是memory
“存储 ”的意思,alloc
是allocate
“开辟 ”的意思
free
是“自由 ”的意思下面我们看一下他们在C语言标准库中的描述
malloc
free
可以看到他们都是在头文件
<stdlib.h>
中的函数
下面是他们的作用,意为"开辟内存空间
"和“释放内存空间
”
那我们来看看具体怎么用吧:
2.1 malloc函数
标准形式:
void* malloc(size_t size);
返回结果
- 如果成功则返回指向开辟的初始地址的指针
- 如果失败则返回NULL这个空指针
- 如果
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
为什么两种情况下会不一样呢?
- 在 x64 环境下,系统理论上可以访问非常大的虚拟地址空间(最大可达 2^64 字节),相比 x86 环境,它能利用的内存资源更充足。
- 在 x86 环境(32 位系统)下,系统能访问的虚拟地址空间最大为 4GB ,这就导致了
malloc
函数必然申请不到足够的连续的内存空间。
2.2 free函数
标准形式:
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; // 实际访问已释放内存
}
3. calloc函数和realloc函数
同malloc函数一样,他们两个函数都是用来开辟内存空间的
calloc
函数中c
是clear
“清零 ”的意思,realloc
函数是reallocate
“重新分配 ”的意思依旧是看从语言标准库中的描述:
calloc
realloc
依旧是头文件
<stdio.h>
中的函数
calloc
与malloc
效果唯一不同的一点就是他会把开辟的内存空间全部初始化成0
realloc
则是对已有的空间进行重开辟
3.1 calloc函数
这里就直接演示一下:
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
3.2 realloc函数
realloc
函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太⼩了,有时候我们⼜会觉得申请的空间过⼤了,那为了合理的使⽤内存,我们⼀定会对内存的⼤⼩做灵活的调整。
那realloc
函数就可以做到对动态开辟内存⼤⼩的调整。
void* realloc (void* ptr, size_t size);
ptr
是指向要调整的地址的指针
size
是调整后的空间大小
返回值为指向调整后的地址的指针
但是
realloc
实际上会有两种情况:
这就导致会有不一样的结果:
- 当是情况1的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化。
- 当是情况2的时候,原有空间之后没有⾜够多的空间时,扩展的⽅法是:在堆空间上另找⼀个合适⼤⼩的连续空间来使⽤。这样函数返回的是⼀个新的内存地址
使用案例:
//代码一,ptr是原开辟地址
ptr = (int*)realloc(ptr, 1000);
//代码二
int* p = NULL;
p = realloc(ptr, 1000);
if (p != NULL)
{ptr = p;
}
这两种代码是对于原地址的两种处理结果
需要注意的是,第一种一旦发生空间不够位置改变,原来的数据就很难再找回来了
所以正确的应该是第二种
- 以上就是四种动态内存管理的基础知识了,希望对大家有所帮助
- 本节完…