当前位置:   article > 正文

C语言:动态内存管理(二)

C语言:动态内存管理(二)

目录

前言

1.3 realloc​编辑

3、常见动态内存管理错误

3.1 对空指针的解引用操作

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

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

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

3.5 对同一块空间的多次释放

3.6 动态内存开辟之后忘记释放

总结


前言

        接上篇继续往下将。

1.3 realloc

        realloc是调整内存空间的函数,就是用来调整内存空间的大小。参数有两个,第一个参数是指向要调整空间的起始位置;第二个参数是新的大小,希望把原来的空间调整到多大,这里就填多少(直接)。

        下面看一个例子:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. int main()
  6. {
  7. int* p = (int*)malloc(40);
  8. if (NULL == p)
  9. {
  10. printf("%s", strerror(errno));
  11. return 1;
  12. }
  13. //使用
  14. int i = 0;
  15. for (i = 0;i < 10;i++)
  16. {
  17. *(p + i) = i + 1;
  18. }
  19. for (i = 0;i < 10;i++)
  20. {
  21. printf("%d ", *(p + i));
  22. }
  23. //扩容
  24. int* pn = (int*)realloc(p, 80);
  25. if (pn != NULL)
  26. {
  27. p = pn;
  28. }
  29. //使用
  30. printf("\n");
  31. for (i = 0;i < 20;i++)
  32. {
  33. *(p + i) = i + 1;
  34. }
  35. for (i = 0;i < 20;i++)
  36. {
  37. printf("%d ", *(p + i));
  38. }
  39. return 0;
  40. }

        在这个例子里面,我们首先用malloc建立了一块大小为40字节的空间,赋值10个整型,观察输出;后又用realloc将原有空间扩大到80字节,最后对空间赋值了20个整型,观察输出。我们来看看运行结果:

        可以看到,realloc成功将原有的40字节空间扩大到了80字节,以便我们存放20个整型数据。

        在这里要注意的是,在扩容时(也就是使用realloc函数时),我们要对新产生的指针进行判断,因为有可能扩容空间太大导致开辟不成功,计算机会返回空指针。所以有了上面的两行代码:

  1. int* pn = (int*)realloc(p, 80);
  2. if (pn != NULL)
  3. {
  4. p = pn;
  5. }

        这样能保证在扩容不成功的情况下,p指针还能保留原来40字节空间及其内容。

        关于realloc的功能,除了能对内存进行扩容以外,还可以进行空间开辟,只需要在传递指针参数的时候传递一个空指针即可。如果这么做,那么它的功能就相当于malloc。

        realloc就讲到这了。

3、常见动态内存管理错误

3.1 对空指针的解引用操作

        以前一篇里面对malloc的使用代码为例:

  1. #include <stdio.h>
  2. #include <errno.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. int main()
  6. {
  7. //动态内存开辟
  8. int* p = (int*)malloc(40);
  9. if (p == NULL) //判断是否开辟成功,开辟失败就报错。
  10. {
  11. printf("%s\n", strerror(errno));
  12. return 1;
  13. }
  14. //使用
  15. int i = 0;
  16. for (i = 0;i < 10;i++)
  17. {
  18. *(p + i) = i;
  19. }
  20. for (i = 0;i < 10;i++)
  21. {
  22. printf("%d ", *(p + i));
  23. }
  24. //空间释放
  25. free(p);
  26. p = NULL;
  27. return 0;
  28. }

        我们在使用之前,先要对定义的p进行判断,看malloc是否成功开辟空间。如果申请空间太大了超过了计算机能承担的范围,就会开辟失败,那malloc返回的将会是一个空指针,p也就为空,那我们如果不加判断直接使用p的时候,就会对其进行接引用,这样做就很危险。

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

        动态开辟的空间也是有大小的,假设我们用malloc开辟了一个40字节的空间,那么对于整型变量,最多存放10个,当我们去访问第11个整型的时候,就会造成越界访问。

        动态内存虽然叫动态内存,但它是需要我们自己去操作才能实现动态的效果的,比如上面说的,如果要去存放第11个整型,我们只需要用到calloc对原来的内存进行加长,就可以了。

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

        对于free这个函数,它只能配合函数malloc、calloc、raelloc使用,对于一般的指针指向的内容,是不能用free释放的。原因在于,malloc、calloc、realloc函数创建的内存其实和一般的变量创建的内存的位置不一样,前者在堆区,后者在栈区,他们是有区别的。一旦用free去释放一个非动态开辟的内存时,就会报错。

        例如:

  1. int main()
  2. {
  3. int a = 10;
  4. int* p = &a;
  5. free(p);
  6. p = NULL;
  7. return 0;
  8. }

        这样的程序一旦运行,就会报错。

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

        直接上例子:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. int man()
  6. {
  7. int* p = (int*)malloc(40);
  8. if (NULL == p)
  9. {
  10. printf("%s", strerror(errno));
  11. return 1;
  12. }
  13. //使用
  14. int i = 0;
  15. for (i = 0;i < 10;i++)
  16. {
  17. *p = i;
  18. p++;
  19. }
  20. //释放
  21. free(p);
  22. p = NULL;
  23. return 0;
  24. }

        像这样的程序,当我们使用完p之后,p将会指向malloc开辟的空间的第十个元素的位置,这时候对p进行free是不行的,如果要用free,就要一次性将整个malloc开辟的空间进行释放,指针必须是指向这块空间的首元素的。

3.5 对同一块空间的多次释放

        这个比较好理解,我们可能会对同一块空间多次释放,这时候也是会报错的。因为第一次释放后指针指向的空间已经被回收了,但是指针任然指向原来的地址,它变成了一个野指针,再一次释放就找不到空间去释放。但如果我们在释放空间后顺便把指针指向空指针,那么再释放一次就也没有问题了。

3.6 动态内存开辟之后忘记释放

        每一次用malloc、calloc、realloc开辟动态内存的时候,在使用完成后,一定记得对其进行释放,做事情要有头有尾。如果忘记释放的话,就会造成内存泄漏,在整个程序结束前,这块内存会一直被占用,在程序结束前都无法再利用这块空间。这样的内存多了,就会导致计算机性能下降 。

总结

        关于动态内存管理的内容就讲到这。希望对你有所帮助。

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

闽ICP备14008679号