目录

C语言动态内存管理详解

C语言动态内存管理详解


(一)堆区

https://i-blog.csdnimg.cn/direct/738d1d6bc5d34ecc96991475ee43fb82.png C语言的内存分为这五个区。 **第一个区是栈区,用来存放函数内部的局部变量的,包括形参,返回值等。

第二个区是堆区,也是本文的重点内容。堆区是用来分配动态内存的,我们本文介绍的动态内存函数申请的内存都是在堆区。**

第三个区是静态区,用来存放全局变量的。 **第四个区是常量区,比如字符串等就存放在里面,而且里面的内存存放的数据不能改变,相同值的地址是相同的。

第五个区是代码区,用来存放我们的程序的代码。**

(二)malloc函数

动态内存函数的头文件都是<stdlib.h>。 https://i-blog.csdnimg.cn/direct/6e7f903049b5431da3875b1a2a9aa9ee.png malloc函数的作用是向堆区申请类型size_ t size的字节,并返回申请内存的首地址。如果申请失败,返回NULL指针。 *首地址为void ,因为函数并不知道申请的地址要存放什么类型的数据,我们一般使用动态内存也必须要强制类型转换才能使用。 下面是malloc的使用说明

//比如申请一片字节为40的字节,存放int类型的数据
size_ t nums = 40;//40字节
int* pa = (int*)malloc(nums);//强制类型转换malloc返回的地址的类型,变得可供使用。

(三)calloc函数

calloc函数和malloc函数的作用大致相同。 与malloc不同的是,calloc申请字节后并将申请的字节的数据全是初始化为0。而且参数也不同了。第一个参数是元素的个数,第二个参数是每个元素的大小。 https://i-blog.csdnimg.cn/direct/ed55c522148040a9b08b91de1d7e8da4.png 下面是calloc的使用

//申请十个int元素的内存
size_t nums = 10;//10个元素
int* pa = (int*)calloc(nums, sizeof(int));//申请nums个元素,每个元素大小是sizeof(int)
(四)realloc函数

realloc函数是重新分配内存的函数。 https://i-blog.csdnimg.cn/direct/52c9a19e18044aee853e5db65b115922.png 第一个参数是一个类型为void*的指针,第二个参数是重新分配的字节大小。返回是重新分配内存后的内存的首地址(需要类型转换使用)。分配成功有两个情况,第一种情况是直接在原地址追加内存(那一片后面的内存足够),第二个情况是重新再堆区找一片合适的内存(后面的内存不足) https://i-blog.csdnimg.cn/direct/7f832ff7a76f401a88557feb0c19570c.png realloc的使用

//将动态内存申请40字节的pa指针重新申请80个字节
size_t nums = 40;
int* pa = (int*)malloc(nums);
//使用realloc函数
if (pa == NULL)
{
    perror("malloc:");
    exit(1);
}//如果申请失败打印失败信息
pa = (int*)realloc(pa, nums * 2);//重新分配内存
(五)free函数

动态申请的内存并不会自己释放,而是由程序员管理的。如果动态申请的内存不释放,可能会导致严重的问题,比如内存泄漏,内存占用严重卡顿。所以我们每次使用完动态内存后必须使用free函数释放。 https://i-blog.csdnimg.cn/direct/dd2beb394b2c44b4a14c8fba0e7393cd.png 参数就是待释放动态内存的指针。

(六)常见问题

对NULL指针的解引⽤操作

void test()
{
    int *p = (int *)malloc(INT_MAX/4);
    *p = 20;//如果p的值是NULL,就会有问题
    free(p);
}

对动态开辟空间的越界访问

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);
}

对非动态开辟内存使用free释放

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

free释放⼀块动态开辟内存的⼀部分

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

对同⼀块动态内存多次释放

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

动态开辟内存忘记释放(内存泄漏)

void test()
{
    int *p = (int *)malloc(100);
    if(NULL != p)
    {
    *p = 20;
    }
}
int main()
{
    test();
    while(1);
}