当前位置:   article > 正文

C语言之动态内存管理(动态内存函数)_c程序动态释放空间的函数

c程序动态释放空间的函数

我们开辟空间的时候,空间的大小是固定的。
在数组申明的函数,必须要指定数组的长度,它所需要的内存在编译时分配的。
但是如果想要开辟不固定大小的空间,该怎么办?
解决方式就是动态进行内存的分配,即在堆上开辟空间。
本篇博客将介绍如何动态开辟空间。

一、动态内存函数

C语言中与动态内存管理相关的函数,主要有四个malloc、free、calloc和realloc。

1.malloc

void* malloc(size_t size);
该函数是开辟一个大小为size字节大小的空间。
返回值:若开辟失败,则返回一个NULL指针,因此malloc的返回值一定要作检查。若开辟成功,则返回这块空间的指针,因为该指针为void*类型,所以具体使用时可以进行强转。

2.free

void free(void* ptr);
该函数是用来释放ptr指针指向的一块空间的。
如果参数ptr指向的空间不是动态开辟的,则free函数的行为是未定义的。
若果参数ptr是NULL指针,则该函数什么都不做。
一般用了malloc申请空间,在使用之后一定要释放该空间,不然会造成资源泄露。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. //malloc和free函数在该头文件里
  4. int main()
  5. {
  6. int num = 0;
  7. scanf("%d", &num);
  8. int* ptr = (int*)malloc(num * sizeof(int));
  9. if (NULL != ptr)
  10. {
  11. for (int i = 0; i < num; ++i)
  12. {
  13. *(ptr + i) = i;
  14. printf("%d ", *(ptr + i));
  15. }
  16. printf("\n");
  17. }
  18. free(ptr);
  19. ptr = NULL;//防止其成为野指针
  20. system("pause");
  21. return 0;
  22. }


最后一定要ptr设为NULL,不然会变成野指针。

3.calloc

void* calloc (size_t num, size_t size);
该函数功能是为num个大小为size的元素开辟一块空间,并且开辟完之后该空间的每个字节都会初始化为0。
其实该函数就是malloc加上初始化。
返回值:若开辟失败,则返回一个NULL指针。若开辟成功,则返回这块空间的指针,因为该指针为void*类型,所以具体使用时可以进行强转。
其开辟完空间,在这个空间使用完之后也一定要调用free函数将其释放掉。

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. //calloc和free函数在该头文件里
  5. int main()
  6. {
  7. int num = 0;
  8. scanf("%d", &num);
  9. //int* ptr = (int*)malloc(num * sizeof(int));
  10. int* ptr = (int*)calloc(num, sizeof(int));
  11. if (NULL != ptr)
  12. {
  13. printf("使用之前,会自动初始化:\n");
  14. for(int i = 0; i < num; ++i)
  15. {
  16. printf("%d ", *(ptr + i));
  17. }
  18. printf("\n");
  19. printf("使用之后:\n");
  20. for(int i = 0; i < num; ++i)
  21. {
  22. *(ptr + i) = i;
  23. printf("%d ", *(ptr + i));
  24. }
  25. printf("\n");
  26. }
  27. free(ptr);
  28. ptr = NULL;
  29. system("pause");
  30. return 0;
  31. }

在这里插入图片描述

不难发现,该函数作用和malloc一样,只不过比malloc多了一个初始化。

4.realloc

void* realloc (void* ptr, size_t size);
该函数是当我们发现过去申请的空间太小了、或者太大了的时候,可以用该函数对动态开辟内存大小调整。
ptr是要调整的空间的指针。
size是调制之后的新大小。
返回值为调整之后的内存起始位置。
该函数在调整原内存空间大小的基础上,还会将原来内存中的数据移到新的空间中。
realloc在调整内存空间时会出现两种情况:①原有空间之后本身就有足够大的空间,此时只需要在原有内存之后直接追加空间,原来空间的数据不发生变化。 ②原有空间之后没有足够大的空间,此时要在堆上重新找一个适合大小的连续空间进行使用,此情况下函数返回的是一个新的内存地址。

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <stdlib.h>//ralloc和free函数在该头文件里
  4. int main()
  5. {
  6. int* ptr = (int*)malloc(5 * sizeof(int));
  7. if (NULL != ptr)
  8. {
  9. for (int i = 0; i < 5; ++i)
  10. {
  11. *(ptr + i) = i;
  12. printf("%d ", *(ptr + i));
  13. }
  14. printf("\n");
  15. }
  16. //用realloc扩容
  17. int* ptr2 = NULL;
  18. ptr2 = (int*)realloc(ptr, 6 * sizeof(int));
  19. if (NULL != ptr2)
  20. {
  21. ptr = ptr2;
  22. }
  23. //之前的数据都在
  24. *(ptr + 5) = 5;
  25. for (int i = 0; i < 6; ++i)
  26. {
  27. printf("%d ", *(ptr + i));
  28. }
  29. printf("\n");
  30. free(ptr);
  31. ptr = NULL;
  32. system("pause");
  33. return 0;
  34. }

在这里插入图片描述

二、常见的动态内存错误

对NULL指针的解引用

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int main()
  5. {
  6. int* ptr = (int*)malloc(2 * sizeof(int));
  7. *ptr = 20;//不判断
  8. free(ptr);
  9. ptr = NULL;
  10. system("pause");
  11. return 0;
  12. }


此时没有对ptr进行判断,则申请失败时ptr值为NULL,那么就会有问题。

对动态开辟空间越界访问

  1. #include <stdio.h>
  2. #include <stdlib.h>//malloc和free函数在该头文件里
  3. int main()
  4. {
  5. int* ptr = (int*)malloc(5 * sizeof(int));
  6. if (NULL != ptr)
  7. {
  8. for (int i = 0; i < 6; ++i)
  9. {
  10. *(ptr + i) = i;
  11. printf("%d ", *(ptr + i));
  12. }
  13. printf("\n");
  14. }
  15. free(ptr);
  16. ptr = NULL;
  17. system("pause");
  18. return 0;
  19. }

上面 *(ptr + 5) 就是越界访问了。

对不是动态开辟的内存使用了free函数进行释放

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. int i = 20;
  6. int* ptr = &ii;
  7. free(ptr);//
  8. ptr = NULL;
  9. system("pause");
  10. return 0;
  11. }

此时程序会崩。

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

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. int* ptr = (int*)malloc(5 * sizeof(int));
  6. if (NULL != ptr)
  7. {
  8. for (int i = 0; i < 6; ++i)
  9. {
  10. *(ptr + i) = i;
  11. printf("%d ", *(ptr + i));
  12. }
  13. printf("\n");
  14. }
  15. free(ptr);
  16. free(ptr);
  17. ptr = NULL;
  18. system("pause");
  19. return 0;
  20. }

此时程序会崩。

使用free函数释放一块动态开辟内存的一部分

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <stdlib.h>//malloc和free函数在该头文件里
  4. int main()
  5. {
  6. int* ptr = (int*)malloc(5 * sizeof(int));
  7. ++ptr;//ptr不再指向该动态内存的起始位置了。
  8. free(ptr);
  9. ptr = NULL;
  10. system("pause");
  11. return 0;
  12. }

程序依旧会崩。

当我们动态开辟内存空间时,使用完之后忘记使用free函数释放之后就会造成内存泄漏。

三、C语言内存开辟


C语言中程序的内存区域划分

栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。


堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于链表。


数据段(静态区)(static):存放全局变量、静态数据。程序结束后由系统释放。


代码段:存放函数体(类成员函数和全局函数)的二进制代码。
————————————————
版权声明:本文为CSDN博主「Sheena爽」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Sheena997/java/article/details/103701171

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/592231
推荐阅读
相关标签
  

闽ICP备14008679号