开篇备忘录: "自给自足的光, 永远都不会暗"
目录
- [1. malloc和free](#1. malloc和free)
-
- [1.1 malloc](#1.1 malloc)
- [1.2 free](#1.2 free)
- [2. calloc和realloc](#2. calloc和realloc)
-
- [2.1 calloc](#2.1 calloc)
- [2.2 realloc](#2.2 realloc)
- [3. 总结C/C++中程序内存区域划分](#3. 总结C/C++中程序内存区域划分)
正文开始
1. malloc和free
1.1 malloc
C语言提供了一个动态开辟内存的函数;
void* malloc (size_t size);
这个函数向内存申请一块连续可用的空间, 并返回指向这块空间的指针.
- 如果内存开辟成功, 则返回一个指向开辟好空间的指针
- 如果开辟失败, 则返回一个NULL指针, 因此malloc的返回值一定要做检查
- 返回值的类型是void* ,所以malloc函数并不知道开辟空间的类型, 具体在使用的时候使用者自己来决定
- 如果参数size为0, malloc的行为标准是未定义的, 取决于编译器
1.2 free
C语言提供了另外一个函数free, 专门是用来做动态内存释放和回收的, 函数原型如下:
void free (void* ptr);
free函数用来释放动态开辟的内存.
- 如果参数ptr指向的空间不是动态开辟的, 那free函数的行为是未定义的.
- 如果参数ptr指向的是NULL指针, 则函数什么事都不用做.
malloc 和 free 都声明在stdlib.h 头文件中
c
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(sizeof(int) * 10);
if (ptr != NULL)
{
for (int i = 0; i < 10; i++)
{
*(ptr + 1) = 0;
}
}
free(ptr);
ptr = NULL;
return 0;
}
2. calloc和realloc
2.1 calloc
C语言还提供了一个函数叫做calloc, calloc函数也用来动态内存分配, 原型如下:
void* calloc (size_t num, size_t size);
- 函数的功能是为num个大小为size的元素开辟一块空间, 并且把空间的每个字节都初始化为0
- 与函数malloc的区别在于calloc会返回地址之前把申请的空间的每个字节初始化为0
c
int main()
{
int* p = calloc(10, sizeof(int));
if (p != NULL)
{
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
}
free(p);
p = NULL;
return 0;
}
运行程序:
所以如果我们对申请的内存空间的内容要求初始化, 那么可以很方便的使用calloch函数来完成任务.
2.2 realloc
- realloc函数的出现让动态内存管理更加灵活
- 有时候我们发现过去申请的空间太小了, 有时候我们又会觉得申请的空间过大了, 那为了合理的使用内存, 我们一定会对内存的大小做灵活调整. 那realloc函数就可以做到对动态开辟内存大小的调整
函数原型如下:
void* realloc (void* ptr, size_t size);
- ptr 是要调整的内存地址
- size 调整之后新的大小
- 返回值为调整之后的内存起始位置
- 这个函数原内存空间大小的基础上, 还会将内存中的数据移动到新的空间
- realloc 在调整内存空间的时候存在两种情况:
-
- 原有的空间之后有足够大的空间
-
- 原有的空间之后没有足够大的空间
两种情况如下图所示:
情况1:
要扩展内存就直接原有内存之后直接追加空间, 原来空间的数据不发生变化
情况2:
原有的空间之后没有足够多的空间, 扩展的方法是: 在堆空间上寻找另外一个1合适大小的连续空间来使用, 这样函数返回的就是一个新的内存的地址
由于上述两种情况, realloc函数的使用就要注意一些:
c
int main()
{
int* ptr = (int*)malloc(100);
if (ptr != NULL)
{
//业务处理
}
else
{
return 1;
}
//扩充容量
//代码1 - 直接将realloc的返回值放到ptr中
ptr = (int*)realloc(ptr, 100);//(可以吗? , 如果开辟内存失败又会如何?)
//代码2 - 先将realloc函数的返回值放在p中, 不为NULL,再放在ptr中
int* p = NULL;
p = realloc(ptr, 1000);
if (p != NULL)
{
ptr = p;
}
//业务处理
free(ptr);
free(p);
ptr = NULL;
p = NULL;
return 0;
}
3. 总结C/C++中程序内存区域划分
C/C++ 程序内存分配的几个区域:
1.栈区(stack): 在执行函数的时候, 函数内局部变量的存储单元都可以在栈上创建,
函数执行结束时这些存储单元自动被释放, 栈内存分配运算内置于处理器的指令集中,
效率很高, 但是分配的内存容量有限, 栈区主要存放运行函数时而分配的局部变量,
函数参数, 返回数据, 返回地址等. 这里推荐一本书<<函数栈帧的创建和销毁>>
2.堆区(heap): 一般由程序员分配释放, 若程序员不释放, 程序结束时可能由
OS(操作系统)回收,分配方式类似于链表
3.数据段(静态区): (static) 存放全局变量, 静态数据, 程序结束后由操作系统释放.
4. 代码段: 存放函数体(类成员函数和全局函数)的二进制代码.
完
本文内容到此结束, 还望读者点赞关注.