当前位置:网站首页>C语言-动态内存管理
C语言-动态内存管理
2022-07-27 05:20:00 【秋名山车神ae】
动态内存开辟函数 malloc与动态内存释放函数free:
void* malloc (size_t size);使用malloc开辟空间时,需传递一个size_t类型的参数作为需要开辟的内存空间的大小(以字节为单位)
malloc函会返回一个void*类型的指针,指向开辟好的空间的起始位置
若开辟失败,则返回空指针NULL(所以返回后要做好检查。)
使用时需注意,开辟好后需要保存好返回的起始位置地址,
在使用完该空间后,需要使用free函数对该空间进行释放,否则会造成内存泄露。
void free (void* ptr);如果起始位置地址未被保存,则该空间将无法被释放。
free函数不能释放非动态内存开辟的空间,free函数不能释放动态内存开辟空间的一部分。
若传入free函数的是空指针,那么函数什么都不会做。
free函数其实是把对内存空间的操作权换给了操作系统,改空间可能还是存在,但是若free后依旧留着该空间的地址,这个地址就是野指针,为了避免野指针的出行,我们在free后应把改指针置为NULL。
free(p);
p=NULL;calloc函数:
calloc函数可以动态开辟一块元素个数为为num,每个元素大小为size的内存空间,并将所有元素的值初始化为0。其余和malloc相同。
void *calloc(size_t num,size_t size);realloc函数:
realloc函数是对已开辟好的动态内存空间进行扩容
传入realloc函数的是需要调整的动态内存空间的起始地址,以及调整后的新的空间大小
void* realloc (void* ptr, size_t size);如果在起始位置后有足够的空间扩容,那么扩容后返回的会是原来的地址;
如果在起始位置后没有足够的空间扩容,那么realloc函数会在内存空间寻找一块合适的位置,将原空间的内容移动至新的空间,并返回新的空间的其实地址;若扩容失败,则返回NULL。
常见的一些动态内存开辟的错误
1.对开辟失败返回的NULL指针进行解引用操作:
void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}所以在对返回的地址进行解引用操作前应先判断是否为空指针。
2.对动态开辟空间的越界访问
void test()
{
int i = 0;
int *p = (int *)malloc(10*sizeof(int));
if(NULL == p)
{
exit(EXIT_FAILURE);
}
for(i=0; i<=10; i++)
{
*(p+i) = i;//当i是10的时候越界访问
}
free(p);
}在操作时应做好检查防止越界访问。
3. 对非动态开辟内存使用free释放
void test()
{
int a = 10;
int *p = &a;
free(p);//ok?
}
4 使用free释放一块动态开辟内存的一部分
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
5.对同一块动态内存多次释放
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
6. 动态开辟内存忘记释放(内存泄漏)
void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
}
int main()
{
test();
while(1);
}所以应当做好内存释放,并正确地进行内存释放。
几个常见的笔试题
void GetMemory(char *p) {
p = (char *)malloc(100);
}
void Test(void) {
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}解析:传入getmemory函数的形参是对实参str的临时拷贝,在函数内对形参的操作并不会影响到str,所以正确的做法应该是取str的地址传入函数中,这样在函数内对形参进行解引用就能操作到str。
char *GetMemory(void) {
char p[] = "hello world";
return p; }
void Test(void) {
char *str = NULL;
str = GetMemory();
printf(str);
}解析:getmemory函数中的字符串常量p存放在栈区中,字符串首元素的地址虽然传入了str;但对函数的调用结束,这块空间就被销毁,str中存放的地址变成了野指针,对野指针进行解引用自然是不行的。
void GetMemory(char **p, int num) {
*p = (char *)malloc(num);
}
void Test(void) {
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}解析:getmemory函数和str没有问题 真正的问题是在使用完毕后没有对动态内存开辟的空间进行free操作。
void Test(void) {
char *str = (char *) malloc(100);
strcpy(str, "hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}
}解析:free后未将str置为NULL,导致str成为野指针,对野指针进行了解引用操作。
对str是否为NULL的判断语句应放在动态开辟内存语句的后面。
free后将str置为NULL。
C/C++程序内存分配的几个区域:
1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结
束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是
分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返
回地址等。
2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分
配方式类似于链表。
3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。普通的局部变量在栈区创建,出了函数就被销毁。全局变量和被static修饰的局部变量存放在静态区,直到程序结束才会被销毁,所以被static修饰的局部变量的生命周期会变长。
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;
有些编译器可能会报错可以改成
typedef struct st_type
{
int i;
int a[];//柔性数组成员
}type_a;柔性数组成员前面必须包含至少一个其他成员。sizeof返回的结构的大小不包含柔性数组成员的大小。包含柔性数组成员的结构的内存用malloc进行动态开辟,分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
例如
typedef struct st_type
{
int i;
int a[0];
}type_a;
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
这样开辟的柔性数组成员可以存放100个int类型的元素。实现柔性数组的方法也可以使用结构体内部放一个指针,但相对于结构体内放指针,柔性数组释放动态开辟的内存只需要释放一次,更具优点。
边栏推荐
- 【头歌】重生之我在py入门实训中(6):函数的定义与应用
- pytorch的多GPU训练的两种方式
- geonode geoserver win10 安装教程(亲测)
- 19. Up and down sampling and batchnorm
- 子类调用父类构造函数的时机
- 【头歌】重生之我在py入门实训中(1)
- 维度问题以及等高线
- [concurrent programming series 9] priorityblockingqueue, delayqueue principle analysis of blocking queue
- 韦东山 数码相框 项目学习(三)freetype的移植
- 使用-Wall清除代码隐患
猜你喜欢
随机推荐
李宏毅 2020 深度学习与人类语言处理 DLHLP-Coreference Resolution-p21
QGIS系列(1)-QGIS(server-apache) win10安装
Cesium教程 (1) 界面介绍-3dtiles加载-更改鼠标操作设置
2021-06-26
LaTeX中多个公式公用一个序号时
Live Home 3D Pro室内家居设计工具
geonode geoserver win10 安装教程(亲测)
韦东山 数码相框 项目学习(三)freetype的移植
解决conda install 安装停止、中断问题
小技巧-彻底删除U盘中的文件
【头歌】重生之数据科学导论——回归进阶
制作视频后期特效需要什么工具?
Gbase 8C - SQL reference 6 SQL syntax (9)
Lightroom Classic 2022 v11.4中文版「最新资源」
7. Merger and division
AE 3D particle system plug-in: Trapcode particle
AE 3D粒子系统插件:Trapcode Particular
socket编程一:使用fork()实现最基础的并发模式
What has been updated in the Chinese version of XMIND mind map 2022 v12.0.3?
判断是否为回文结构的三种方法









