动态内存管理

本章重点
一、为什么存在动态内存分配
二、动态内存函数的介绍
        malloc
        free        
        calloc
        realloc
三、常见的动态内存错误
四、柔性数组

一、为什么存在动态内存分配

因为在实际的开发过程中,有时候需要的内存空间并不需要太大,我们需要的是一种动态改变的空间。例如,实现一个通讯录代码的时候往往需要创建一个存放联系人的数组,如果没有动态内存分配,可能就会产生两种情况:

1.数组满了放不进联系人,需要手动修改数组大小

2.完全不需要数组开辟这么大的内存空间,而我们为了防止空间不够多开辟了内存,造成了内存的浪费

二、动态内存分配函数的介绍

0.内存的分配情况

在讲函数之前,我想先介绍一下系统的内存布局:

内存有栈区,堆区,静态区三个区域。其中栈区就是我们存放函数形参和临时变量的地方,也就是临时的数据都是在这开辟的。而malloc relloc calloc这样动态开辟的内存都是在堆区中。静态区也就是存放全局变量和静态变量的地方。 

1.malloc函数

函数全称叫做——memory allocate,也就是内存分配。

 

它的返回值是void*的指针,指向了我们所开辟空间的起始位置,参数size_t size是所要开辟空间的字节数。 

注意:如果内存空间不够的时候,也就是malloc无法向内存申请我们需要的空间,这时候它会返回NULL——一个空指针。像这样:

我们向内存申请了最大整形字节数的空间,显然这是不够的, 这时malloc返回了一个空指针,并且perror打印了错误的原因。

如果向内存申请0字节的空间 这种行为是c语言标准未定义的。

 

头文件:

 具体的使用方法:

#include<stdio.h>
#include<malloc.h>
int main()
{
    int* p = (int*)malloc(10);
    free(p);
    p = NULL;
    return 0;
}

由于malloc返回的是一个void*的指针,真正要使用它的时候需要把它强制类型转换为我们所需的数据类型。

2.free函数

free函数没有返回值,它的参数是指向我们申请的空间起始位置的一个指针。

它的作用是将我们动态申请的内存还给系统,如果我们没有手动free掉我们申请的空间,在程序结束时会由OS自动回收。但是,如果程序无法结束呢?

int main()
{
	while (1)
	{
		malloc(50);
	}
	return 0;
}

如上面的代码,程序进入了一个死循环,不停的在申请内存,造成了内存的浪费,如果系统一直运行,会耗干所有的内存,也就是内存泄漏。

所以使用完一定要记得free掉申请的空间,并且要注意,原本指向我们申请空间的指针会变成野指针,记得要把它置为NULL。

3.calloc函数

 

 其实calloc函数和malloc函数的差别并不是很大,calloc的第一个参数是要申请的元素个数,比如要申请10个int类型的数据就是10,第二个就是单个元素的字节数。

#include<stdio.h>
#include<malloc.h>
int main()
{
    int* p = (int*)calloc(10,4)//申请10个int类型大小的空间
    free(p);
    p = NULL;
    return 0;
}

calloc和malloc最大的区别是calloc在申请空间的时候会帮我们把空间所有字节的数据初始化为0。相反的,malloc在申请空间的时候空间内都是随机值。

malloc申请的空间:

calloc: 

 

 4.realloc函数

 realloc函数用于调整我们所开辟空间的大小。第一个参数是已经开辟的空间的起始位置,第二个参数是调整后的空间大小。

realloc如果想要调小空间,一般不会有太大的问题,如果要调大空间,有两种情况:

1.内存空间足够的时候,它返回的指针就是原来空间的指针。

2.后面的内存空间不足够的时候,它会找到另外一个空间,这个空间足够我们开辟数据,而且它会把在原有空间内已经修改过的数据原原本本搬到新空间中,返回新空间的起始地址。

三、常见的动态内存错误

1.对NULL指针的解引用操作

#include<stdio.h>
#include<malloc.h>
int main()
{    
    int* p = (int*)malloc(40);//申请空间
    *p = 1;//考虑malloc是否会申请空间失败,此时p是一个空指针,对空指针解引用的非法操作
    return 0;
}

正确的做法:
 

#include<stdio.h>
#include<malloc.h>
int main()
{
    int* p = (int*)malloc(40);
    if(p != NULL)
    {
        *p = 1;
    }
    free(p);
    p = NULL;
    return 0;
}

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);
     p = NULL;
}

3.对非开辟的空间进行free操作

free函数只能free掉我们动态开辟的内存。

void test()
{
     int a = 10;
     int *p = &a;
     free(p);//ok?
}

4.对开辟的空间多次free操作

void test()
{
     int *p = (int *)malloc(100);
     free(p);
     free(p);//重复释放
}

5.对开辟的空间free一部分

void test()
{
     int *p = (int *)malloc(100);
     p++;
     free(p);//p不再指向动态内存的起始位置
}

6.忘记释放所开辟的空间

这个上面已经提到了,每次开辟空间后都一定要记得free掉空间,并且指针置空。

这次的介绍就到此结束,柔性数组我放在下一篇博客介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值