源代码

  1. //导入printf函数,用于输出
  2. #include <stdio.h>
  3. //导入assert函数,断言,用于获取内存是否异常
  4. #include <assert.h>
  5. //导入malloc函数,用于内存分配, Allocate SIZE bytes of memory
  6. #include <stdlib.h>
  7. //导入strdup函数,用于字符串的复制
  8. #include <string.h>
  9. struct Person {
  10. char *name;
  11. int age;
  12. int height;
  13. int weight;
  14. };
  15. //从方法的声明上可以看出,该方法的返回值是一个struct Person*,指向Person结构体的指针
  16. struct Person* Person_create(char *name, int age, int height, int weight)
  17. {
  18. //申请指定长度的内存
  19. //sizeof获取的长度是 8 + 4 + 4 + 4 = 20个字节
  20. //name*是一个地址,长度是8个字节,也就是64位的地址
  21. //每个int占用4个字节
  22. struct Person *who = malloc(sizeof(struct Person));
  23. //判断malloc返回是否成功,成功的话,who指针不为空,肯定会指向一个内存块的首地址
  24. //NULL是一个特殊常量,表示“unset or invalid pointer"
  25. assert(who != NULL);
  26. //使用->语法为结构体赋值
  27. //strdup其实和malloc差不多,都是分配一段内存,不过区别是strdup另外还需要将字符串复制到新内存空间中
  28. //strdup在此处的目的是该struct真正的用于该字符串,而不是其他地方也引用,防止被其他地方修改或者释放
  29. who->name = strdup(name);
  30. who->age = age;
  31. who->height = height;
  32. who->weight = weight;
  33. return who;
  34. }
  35. //良好编程习惯:有create的地方,肯定会有释放的地方
  36. void Person_destroy(struct Person *who)
  37. {
  38. //良好编程习惯:在释放前,同样要判断指针是否合法
  39. assert(who != NULL);
  40. //释放字符串和Person对象占用的内容空间
  41. //如果不释放的话,会造成内存泄漏
  42. //free(who->name);
  43. free(who);
  44. }
  45. void Person_print(struct Person *who)
  46. {
  47. printf("Joe-inner function is at memory location %p: \n", &who);
  48. //结构体成员,使用->来访问
  49. printf("Name: %s\n", who->name);
  50. printf("\tAge: %d\n", who->age);
  51. printf("\tHeight: %d\n", who->height);
  52. printf("\tWeight: %d\n", who->weight);
  53. }
  54. int main(int argc, char *argv[])
  55. {
  56. // make two people structures
  57. struct Person *joe = Person_create("Joe Alex", 32, 64, 140);
  58. struct Person *frank = Person_create("Frank Blank", 20, 72, 180);
  59. // print them out and where they are in memory
  60. printf("Joe is at memory location %p: \n", joe);
  61. printf("Joe is at memory location %p: \n", &joe);
  62. Person_print(joe);
  63. printf("Frank is at memory location %p: \n", frank);
  64. Person_print(frank);
  65. // make everyone agr 20 years and print them again
  66. joe->age +=20;
  67. joe->height -=2;
  68. joe->weight +=40;
  69. Person_print(joe);
  70. frank->age +=20;
  71. frank->height +=20;
  72. Person_print(frank);
  73. // destroy them both so we clean up
  74. Person_destroy(joe);
  75. Person_destroy(frank);
  76. return 0;
  77. }

安装valgrind

apt update apt install valgrind

编译程序,并使用valgrind执行

valgrind --leak-check=full ./ex16
输出结果如下:

==11300==
==11300== HEAP SUMMARY:
==11300== in use at exit: 21 bytes in 2 blocks
==11300== total heap usage: 5 allocs, 3 frees, 1,093 bytes allocated
==11300==
==11300== 9 bytes in 1 blocks are definitely lost in loss record 1 of 2
==11300== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11300== by 0x4EDBAF9: strdup (strdup.c:42)
==11300== by 0x10882E: Person_create (ex16.c:33)
==11300== by 0x108966: main (ex16.c:66)
==11300==
==11300== 12 bytes in 1 blocks are definitely lost in loss record 2 of 2
==11300== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11300== by 0x4EDBAF9: strdup (strdup.c:42)
==11300== by 0x10882E: Person_create (ex16.c:33)
==11300== by 0x108985: main (ex16.c:67)
==11300==
==11300== LEAK SUMMARY:
==11300== definitely lost: 21 bytes in 2 blocks
==11300== indirectly lost: 0 bytes in 0 blocks
==11300== possibly lost: 0 bytes in 0 blocks
==11300== still reachable: 0 bytes in 0 blocks
==11300== suppressed: 0 bytes in 0 blocks
==11300==
==11300== For counts of detected and suppressed errors, rerun with: -v
==11300== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

分析

从下面可以看出:

total heap usage: 5 allocs, 3 frees, 1,093 bytes allocated

分配了5次内存,但是只释放3次。
说明有两次没有释放。

==11300== 9 bytes in 1 blocks are definitely lost in loss record 1 of 2 ==11300== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==11300== by 0x4EDBAF9: strdup (strdup.c:42)

==11300== by 0x10882E: Person_create (ex16.c:33)

==11300== by 0x108966: main (ex16.c:66)

此处泄漏了9个字节,是由strdup申请未释放的。

再综合代码,就可以找到未释放的位置,如下:
image.png