• C语言动态内存管理malloc、calloc、realloc、free函数的讲解


    目录

    一.为什么存在动态内存管理:

    二、动态内存函数的介绍:

    1.动态开辟函数——malloc函数

    1.1.函数声明和作用:

    1.2.函数使用实例:

    2.释放动态空间函数——free函数

    2.1.free函数注意事项:

    2.2.free函数使用实例:

    3.动态开辟函数——calloc函数

    3.1.函数的声明和作用:

    3.2.函数使用实例:

    4.动态开辟函数——realloc(最主要、最常用):

    4.1.注意事项:

    4.2.函数声明与作用:

    4.3.函数返回值:有三种情况

    4.4.函数使用实例:


    一.为什么存在动态内存管理:

    我们知道,在此之前向内存申请空间的方式有以下两种:(变量和数组)

    但这两种方法有几个缺陷

    ①:空间开辟大小是固定的;

    ②:数组在声明的时候,必须指定数组的长度,它所需要的内存在编译时分配;

    但是由于空间的需求,不仅仅是上述两种情况,有时候我们需要的空间大小在程序运行的时候才知道,那数组的编译时开辟空间的方式就不合适了。

    假设数组大小为100,但有101个元素就塞不下;只有10个元素又太浪费空间了。

    所以这时候只能试试动态分配了。

    二、动态内存函数的介绍:

    1.动态开辟函数——malloc函数

    1.1.函数声明和作用:
    void* malloc (size_t size);
    

    ①:函数作用:向内存申请一块可用的连续的空间,返回值为这块空间的起始地址;

    ②:函数参数:类型为size_t,即该函数一次申请size个字节的空间,但不会初始化该空间内容,如果size==0,那么malloc的行为是未定义的,取决于编译器;

    ③:返回值是void*,返回规则如下:

    ④:该函数包含头文件中。

    ⑤:动态内存函数申请空间都是在堆区上面申请,如下图:

    1.2.函数使用实例:
    1. #include
    2. #include
    3. int main()
    4. {
    5. //要什么类型的空间,就用什么类型的指针接收
    6. //注意函数返回值为void*,所以记住强制类型转换
    7. int* p = (int*)malloc(40);
    8. //判断申请空间是否成功
    9. if (p == NULL)
    10. {
    11. perror("malloc");//打印申请失败的原因
    12. return 1;
    13. }
    14. //使用空间
    15. int i = 0;
    16. for (i = 0; i < 4; i++)
    17. {
    18. p[i] = i;
    19. printf("%d ", p[i]);
    20. }
    21. return 0;
    22. }

    2.释放动态空间函数——free函数

    注意:这些动态开辟函数申请内存空间,当程序退出时,会还给操作系统,但当程序不退出,动态开辟的内存不会主动释放,这时就需要用到函数free()来释放。

    2.1.free函数注意事项:

    ①:函数声明:

    void free (void* ptr);

    ②:该函数包含在头文件中。

    2.2.free函数使用实例:

    该函数使用方法非常简单,参数只需要给动态开辟的变量即可,如下:

    这里值得注意的是,free函数释放空间后,不会改变指针p的值,所以此时p还是指向这块空间,但该空间已被释放,所以此时p是野指针,所以我们要把p指针置空

    3.动态开辟函数——calloc函数

    3.1.函数的声明和作用:
    void* calloc (size_t num, size_t size);

    ①:函数的作用:该函数是动态开辟num个大小为size的空间,并且把空间的每个字节初始化为0;

    ②:返回值和malloc相同,开辟成功返回这块空间的起始地址;开辟失败返回NULL。

    ③:与malloc函数的区别是:该函数为把空间的每个字节初始化0。

    ④:

    3.2.函数使用实例:
    1. int main()
    2. {
    3. //动态开辟五个整型大小的空间
    4. int* p = (int*)calloc(5, sizeof(int));
    5. //检查是否开辟成功
    6. if (p == NULL)
    7. {
    8. perror("calloc");
    9. return 1;
    10. }
    11. //使用空间
    12. for (int i = 0; i < 5; i++)
    13. {
    14. printf("%d ", p[i]);
    15. }
    16. //释放空间
    17. free(p);
    18. p = NULL;
    19. return 0;
    20. }

    运行结果:

    4.动态开辟函数——realloc(最主要、最常用):

    4.1.注意事项:

    realloc函数的出现让动态内存管理更加灵活。

    有时我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,为了合理使用内存,我们就可以用realloc函数动态开辟内存,以便对内存的大小做灵活调整。

    4.2.函数声明与作用:
    void* realloc (void* ptr, size_t size);

    ①:参数介绍:

    第一个参数void*,是指需要调整大小的空间,是之前通过malloc、calloc、realloc函数开辟好的;

    第二个参数size_t szie,是指调整后的新的空间大小,单位为字节;

    ②:当第一个参数ptr为空指针时,效果和malloc相同。

    4.3.函数返回值:有三种情况

    情况一:若str后面还有足够的连续空间,则返回值为str的起始空间。

    情况二:若str后面没有足够的连续空间,则realloc函数会重新找一份足够大的新空间;将旧空间的内容拷贝到新空间;然后释放掉旧空间;最后返回新空间的起始地址。

    情况三:开辟失败,返回NULL。

    4.4.函数使用实例:
    1. int main()
    2. {
    3. //先用malloc开辟5个整型的空间
    4. int* p = (int*)malloc(20);
    5. //检查malloc是否开辟成功
    6. if (p == NULL)
    7. {
    8. perror("malloc");
    9. return 1;
    10. }
    11. //开辟成功后,赋值1,2,3,4,5
    12. int i = 0;
    13. for (i = 0; i < 5; i++)
    14. {
    15. p[i] = i + 1;
    16. }
    17. //用realloc扩容五个整形的空间,所以新空间为40字节
    18. //注意这里别用上面的指针p接收,
    19. //因为如果realloc开辟失败,就会返回空指针给指针p
    20. //指针p改变了,那么之前动态开辟的空间就找不到了,就会存在内存泄漏
    21. int* str =(int*) realloc(p, 40);
    22. //检查是否开辟成功
    23. if (str == NULL)
    24. {
    25. perror("realloc");
    26. return 1;
    27. }
    28. //开辟成功后再赋值给指针p,然后将str置零
    29. p = str;
    30. str = NULL;
    31. //检测是否将旧空间的数据拷贝到新空间
    32. for (i = 0; i < 5; i++)
    33. {
    34. printf("%d ", p[i]);
    35. }
    36. //释放
    37. free(p);
    38. p = NULL;
    39. return 0;
    40. }

    运行结果:

    本次知识到此结束,关于动态内存的知识还没有结束,未完待续!

  • 相关阅读:
    LeetCode 1282. 用户分组
    Beelzebub过程记录及工具集
    【无标题】
    Spring循环依赖
    2023年【上海市安全员C证】考试题库及上海市安全员C证新版试题
    Super easy to understand decision trees (part one)
    第十九章 Nacos统一配置中心详解
    leetcode 547.省份数量 并查集
    排序算法之-选择
    邻接表转化为逆邻接表
  • 原文地址:https://blog.csdn.net/hffh123/article/details/133324322