[经验分享] C语言:动态内存管理

[复制链接]
2|0
Jiangxiaopi 发表于 2026-7-4 17:45 | 显示全部楼层 |阅读模式
一.动态内存分配的意义
我们之前学习开辟空间的大小是固定的,一旦开辟了空间大小就不能调整。

int a = 10;
int arr[20]={0};


所以C语言引入了动态内存开辟,让我们自己申请和释放空间。

因此动态内存分配让C语言程序能够在运行时灵活管理内存,平衡了内存使用的效率与灵活性 ,是实现复杂功能(如操作系统、数据库)的基础。

头文件:

#include<stdlib.h>


二.malloc
1.函数原型

void* malloc(size_t size);
//size_t size:申请内存空间的大小,单位是字节。
//void*:返回void*指针类型,注意强制类型转化


(1)如果开辟成功,则返回一个指向开辟好空间的起始地址。(注意强制类型转化,因为有返回值是void*)

(2)如果开辟失败,则返回NULL指针,因此在使用后要检查指针是否为空指针。

2.使用

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(20);//开辟动态内存,p指向首地址
        if (p == NULL)//判断是否为空指针
        {
                perror("malloc");
                return 1;
        }
        //使用空间
        int i;
        for (i = 0; i < 5; i++)
        {
                *(p + i) = i + 1;
        }
        for (i = 0; i < 5; i++)
        {
                printf("%d ", *(p + i));
        }

        return 0;
}



三.free
1.函数原型

void free(void* ptr);
//void* ptr:释放内存空间的起始地址


(1)ptr指向空间是动态内存开辟的首地址。

(2)如果ptr是NULL指针,则函数什么是都不做。

2.使用

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(20);//开辟动态内存
        if (p == NULL)//判断是否为空指针
        {
                perror("malloc");
                return 1;
        }
        int i;
        for (i = 0; i < 5; i++)//使用动态内存空间
        {
                *(p + i) = i + 1;
        }
        for (i = 0; i < 5; i++)
        {
                printf("%d ", *(p + i));
        }
        //释放空间
        free(p);//将空间还给操作系统
        p = NULL;//防止成为野指针
        return 0;
}



3.注意事项

free里面是起始地址

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(20);
        if (p == NULL)
        {
                perror("malloc");
                return 1;
        }
        int i;
        for (i = 0; i < 5; i++)
        {
                *p= i + 1;
        p++//此时p不是起始地址
        }
        for (i = 0; i < 5; i++)
        {
                printf("%d ", *(p + i));
        }
       
        free(p);//p不是起始地址
        p = NULL;
        return 0;
}



四.calloc
1.定义

void* calloc(size_t num, size_t size);
//size_t num:成员个数
//size_t size:每个成员大小


与malloc区别:

(1)calloc有2个参数。

(2)calloc将空间的每个字节初始化为0。

2.使用

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)calloc(5, sizeof(int));
//使用malloc:int* p=(int*)malloc(5*sizeof(int));
        if (p == NULL)
        {
                perror("calloc");
                return 1;
        }
        //使用动态内存空间
        int i;
        for (i = 0; i < 5; i++)
        {
                *(p + i) = i + 1;
        }
        for (i = 0; i < 5; i++)
        {
                printf("%d ", *(p + i));
        }
        free(p);
        p = NULL;
        return 0;
}



五.realloc
1.定义

void* realloc(void* ptr, size_t size);
//void* ptr:需要修改动态内存空间的首地址
//size_t size:修改后的内存大小
//void*:返回修改后的内存首地址


注意:调整空间存在3种情况:

(1)原有空间之后有足够大空间:直接在原有内存后追加空间,原来空间的数据不发生变化。

(2)原有空间之后没有足够大空间:

在堆空间的另一个位置找到连续空间来使用,释放旧空间,同时返回一个新的首地址。

(3)调整失败,返回是一个NULL。

因此,我们在调整后,需判断返回的指针是否为NULL。

2.使用

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(5 * sizeof(int));
    if(p==NULL)
    {
        perror("malloc");
        return 1;
    }
        /*
        使用动态空间......
        */
        //调整空间大小:
        int* ptr = (int*)realloc(p, 10 * sizeof(int));//注意不能用p指针来接收,
//后面需判断返回是否为空指针
        if (ptr != NULL)
        {
                p = ptr;
        /*
        使用动态内存......
        */
                free(p);
                p = NULL;
        }
        else
        {
                perror("realloc");
                //ptr指针为空指针,但p指针所指向的内存空间仍可以使用
                /*
                使用p指针指向的动态内存
                */
                free(p);
                p = NULL;
        }
        return 0;
}



3.补充

realloc也可以跟malloc一样创建动态内存空间。

int*p = (int*)realloc(NULL,20);//当地址为空指针时,会自动创建一块动态内存空间
int*p = (int*)malloc(20);


六.动态内存分配的常见错误
1.对NULL指针解引用

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(INT_MAX);//当申请的动态内存太大时可能返回NULL
        *p = 20;//没有判断p指针是否为空指针
        free(p);
        p = NULL;
        return 0;
}



总结:申请完动态内存后要判断是否为空指针

2.对动态内存空间的越界访问

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int i = 0;
        int* p = (int*)malloc(10 * sizeof(int));
        if (p == NULL)
        {
                perror("malloc");
                return 1;
        }
        for (i = 0; i <= 10; i++)//当i=10时,动态内存越界访问
        {
                *(p + i) = i;
        }
        free(p);
        p = NULL;
        return 0;
}



总结:注意动态内存大小,不要越界访问

3.对非动态内存空间使用free释放

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int a = 10;
        int* p = &a;//p开辟的不是动态内存
        free(p);
        return 0;
}


总结:注意free释放对象

4.使用free释放一块动态开辟内存的一部分(即free后面跟着的地址不是首地址)

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(10*sizeof(int));
        if (p == NULL)
        {
                perror("malloc");
                return 1;
        }
        int i = 0;
        for (i = 0; i < 10; i++)
        {
                *p = i;
                p++;//p移动了指向的不是首地址
        }
        free(p);//释放时p就不是首地址
        p = NULL;
        return 0;
}



//修改后:
#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(10*sizeof(int));
        if (p == NULL)
        {
                perror("malloc");
                return 1;
        }
        int i = 0;
        for (i = 0; i < 10; i++)
        {
                p[i] = i;//移动后p指向的依然是首地址
        }
        free(p);
        p = NULL;
        return 0;
}



总结:注意free释放对象

5.对同一块动态内存多次释放

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(100);
        free(p);
        //......
        free(p);//有时可能忘记前面释放了,写了很多代码后又释放了一次
        return 0;
}



#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(100);
        free(p);
        p = NULL;//将p置为空指针
        //......
        free(p);
        return 0;
}



总结:释放后要及时置NULL

6.忘记对动态内存释放(会导致内存泄露)

#include<stdio.h>
#include<stdlib.h>
int main()
{
        int* p = (int*)malloc(20);
        if (p == NULL)
        {
                perror("malloc");
                return 1;
        }
        //使用动态内存中......
        //没有释放动态内存
        return 0;
}



#include<stdio.h>
#include<stdlib.h>
int main()
{
        int i = 3;
        int* p = (int*)malloc(20);
        if (i > 0)
        {
                return;//提前返回,即使后面有释放内存空间的代码,但也执行不到
        }
        free(p);
        p = NULL;
        return 0;
}



总结:注意要释放内存同时要执行该代码
————————————————
版权声明:本文为CSDN博主「fffzd」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yyyzc_/article/details/156205328

您需要登录后才可以回帖 登录 | 注册

本版积分规则

152

主题

539

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0