我找不到我的C代码中存在内存泄漏的位置。

huangapple go评论103阅读模式
英文:

I can't find where my C code is having memory leaks

问题

Valgrind reports memory leaks in your code. Specifically, it mentions that 80 bytes in 5 blocks were lost. The issue seems to be in your stack_push function, which allocates memory for a new node but doesn't free it properly when the stack is destroyed.

Here's how you can fix the memory leak issue:

  1. In your stack_destroy function, before freeing the stack itself, make sure to free all the nodes in the stack.
  1. stack stack_destroy(stack s) {
  2. node i = s->first;
  3. while (i != NULL) {
  4. node killme = i;
  5. i = i->next;
  6. killme = destroy_node(killme);
  7. }
  8. free(s); // Now you can free the stack itself
  9. s = NULL;
  10. return s;
  11. }
  1. Ensure that you free the memory allocated for the array returned by stack_to_array in your main function:
  1. int *new_array = NULL;
  2. stack s = stack_empty();
  3. for (int i = length; i > 0; --i) {
  4. s = stack_push(s, array[i - 1]);
  5. }
  6. new_array = stack_to_array(s);
  7. printf("Reversed: ");
  8. array_dump(new_array, length);
  9. stack_destroy(s);
  10. free(new_array); // Free the array memory

By making these changes, you should address the memory leak issue reported by Valgrind.

英文:

I'm trying to implement a "stack" type, and the professor provided the stack.h file and most of the reverse.c code , and my job was to implement stack.c and complete reverse.c. Valgrind says that some memory is leaking but I can't find the error. The code is as follows:

stack.h

  1. /**
  2. * @file stack.h
  3. * @brief TAD Stack definition
  4. */
  5. #ifndef __STACK_H__
  6. #define __STACK_H__
  7. #include <stdbool.h>
  8. /**
  9. * @brief Stack type definition
  10. */
  11. typedef struct _s_stack *stack;
  12. /**
  13. * @brief Stack elements type definition
  14. */
  15. typedef int stack_elem;
  16. /**
  17. * @brief Creates an empty stack
  18. * @return An empty stack
  19. */
  20. stack stack_empty();
  21. /**
  22. * @brief Inserts an element at the top of the stack
  23. * @param s A stack
  24. * @param e An element to push into the stack
  25. * @return The new stack with 'e' at the top
  26. */
  27. stack stack_push(stack s, stack_elem e);
  28. /**
  29. * @brief Removes the element at the top of the stack
  30. * @param s A stack
  31. * @return The new stack with the top element removed
  32. * @note Only applies to non-empty stacks
  33. */
  34. stack stack_pop(stack s);
  35. /**
  36. * @brief Returns the size of the stack
  37. * @param s A stack
  38. * @return The size of the stack
  39. */
  40. unsigned int stack_size(stack s);
  41. /**
  42. * @brief Returns the element at the top of the stacks
  43. * @param s A stacks
  44. * @return The element at the top of the stack
  45. * @note Only applies to non-empty stacks
  46. */
  47. stack_elem stack_top(stack s);
  48. /**
  49. * @brief Check if the given stack is empty
  50. * @param s A stack
  51. * @return true if the stack is empty, false otherwise
  52. */
  53. bool stack_is_empty(stack s);
  54. /**
  55. * @brief Creates an array with all the elements of the stack
  56. * @param s A stack
  57. * @return An array containing all the elements of the stack. The stack top element
  58. * becomes the rightmost element of the array. The size of the resulting
  59. * array is determined by 'stack_size(s)'
  60. */
  61. stack_elem *stack_to_array(stack s);
  62. /**
  63. * @brief Destroys the stack
  64. * @param s A stack
  65. * @note All memory resources are freed
  66. */
  67. stack stack_destroy(stack s);
  68. #endif

stack.c

  1. #include <stdlib.h>
  2. #include <assert.h>
  3. #include "stack.h"
  4. typedef struct _n_node *node;
  5. struct _n_node
  6. {
  7. stack_elem elem;
  8. node next;
  9. };
  10. struct _s_stack {
  11. node first;
  12. unsigned int size;
  13. };
  14. static node create_node(stack_elem e) {
  15. node new_node=malloc(sizeof(struct _n_node));
  16. assert(new_node!=NULL);
  17. new_node->elem = e;
  18. new_node->next = NULL;
  19. return new_node;
  20. }
  21. static node destroy_node(node kill) {
  22. kill->next=NULL;
  23. free(kill);
  24. kill=NULL;
  25. return kill;
  26. }
  27. stack stack_empty() {
  28. stack new_stack;
  29. new_stack = malloc(sizeof(struct _s_stack));
  30. new_stack->size = 0;
  31. new_stack->first = NULL;
  32. return new_stack;
  33. }
  34. stack stack_push(stack s, stack_elem e) {
  35. node new_node = create_node(e);
  36. new_node->next=s->first;
  37. s->first=new_node;
  38. s->size++;
  39. return s;
  40. }
  41. stack stack_pop(stack s) {
  42. assert(s->first!=NULL);
  43. node killme = s->first;
  44. s->first=s->first->next;
  45. s->size--;
  46. killme = destroy_node(killme);
  47. return s;
  48. }
  49. unsigned int stack_size(stack s) {
  50. return s->size;
  51. }
  52. stack_elem stack_top(stack s) {
  53. assert (s->first!=NULL);
  54. return s->first->elem;
  55. }
  56. bool stack_is_empty(stack s) {
  57. return (s->first==NULL);
  58. }
  59. stack_elem *stack_to_array(stack s) {
  60. stack_elem *array = NULL;
  61. array = (stack_elem*)calloc((s->size), sizeof(struct _n_node));
  62. for (int i = ((s->size)-1); i >= 0; --i) {
  63. array[i]=stack_top(s);
  64. s->first=s->first->next;
  65. }
  66. return array;
  67. }
  68. stack stack_destroy(stack s) {
  69. node i=s->first;
  70. while (i!=NULL)
  71. {
  72. node killme=i;
  73. i=i->next;
  74. killme=destroy_node(killme);
  75. }
  76. free(s);
  77. s=NULL;
  78. return s;
  79. }

reverse.c

  1. /* First, the standard lib includes, alphabetically ordered */
  2. #include <assert.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. /* Then, this project's includes, alphabetically ordered */
  6. #include "array_helpers.h"
  7. #include "../stack.h"
  8. /* Maximum allowed length of the array */
  9. static const unsigned int MAX_SIZE = 100u;
  10. void print_help(char *program_name) {
  11. /* Print the usage help of this program. */
  12. printf("Usage: %s <input file path>\n\n"
  13. "Sort an array given in a file in disk.\n"
  14. "\n"
  15. "The input file must have the following format:\n"
  16. " * The first line must contain only a positive integer,"
  17. " which is the length of the array.\n"
  18. " * The second line must contain the members of the array"
  19. " separated by one or more spaces. Each member must be an integer."
  20. "\n\n"
  21. "In other words, the file format is:\n"
  22. "<amount of array elements>\n"
  23. "<array elem 1> <array elem 2> ... <array elem N>\n\n",
  24. program_name);
  25. }
  26. char *parse_filepath(int argc, char *argv[]) {
  27. /* Parse the filepath given by command line argument. */
  28. char *result = NULL;
  29. if (argc < 2) {
  30. print_help(argv[0]);
  31. exit(EXIT_FAILURE);
  32. }
  33. result = argv[1];
  34. return (result);
  35. }
  36. int main(int argc, char *argv[]) {
  37. char *filepath = NULL;
  38. /* parse the filepath given in command line arguments */
  39. filepath = parse_filepath(argc, argv);
  40. /* create an array of MAX_SIZE elements */
  41. int array[MAX_SIZE];
  42. /* parse the file to fill the array and obtain the actual length */
  43. unsigned int length = array_from_file(array, MAX_SIZE, filepath);
  44. printf("Original: ");
  45. array_dump(array, length);
  46. /* my code: */
  47. int *new_array=NULL;
  48. stack s = stack_empty();
  49. for (int i=length; i>0; --i) {
  50. s = stack_push (s, array[i-1]);
  51. }
  52. new_array = stack_to_array(s);
  53. printf("Reversed: ");
  54. array_dump(new_array, length);
  55. stack_destroy(s);
  56. free(new_array);
  57. /* end of my code */
  58. return (EXIT_SUCCESS);
  59. }

When running through valgrind, I get the following transcript:

  1. $ valgrind -s --leak-check=full ./reverse ./input/example-easy.in
  2. ==81== Memcheck, a memory error detector
  3. ==81== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
  4. ==81== Using Valgrind-3.21.0 and LibVEX; rerun with -h for copyright info
  5. ==81== Command: ./reverse ./input/example-easy.in
  6. ==81==
  7. Original: [1, 2, 3, 4, 5]
  8. Reversed: [5, 4, 3, 2, 1]
  9. ==81==
  10. ==81== HEAP SUMMARY:
  11. ==81== in use at exit: 80 bytes in 5 blocks
  12. ==81== total heap usage: 10 allocs, 5 frees, 5,768 bytes allocated
  13. ==81==
  14. ==81== 80 (16 direct, 64 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
  15. ==81== at 0x484880F: malloc (vg_replace_malloc.c:431)
  16. ==81== by 0x1092E1: create_node (stack.c:19)
  17. ==81== by 0x1093B8: stack_push (stack.c:42)
  18. ==81== by 0x1097F0: main (reverse.c:61)
  19. ==81==
  20. ==81== LEAK SUMMARY:
  21. ==81== definitely lost: 16 bytes in 1 blocks
  22. ==81== indirectly lost: 64 bytes in 4 blocks
  23. ==81== possibly lost: 0 bytes in 0 blocks
  24. ==81== still reachable: 0 bytes in 0 blocks
  25. ==81== suppressed: 0 bytes in 0 blocks
  26. ==81==
  27. ==81== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)```
  28. </details>
  29. # 答案1
  30. **得分**: 2
  31. 以下是您要翻译的代码部分:
  32. 问题出在这个无效的函数上
  33. ```c
  34. stack_elem *stack_to_array(stack s) {
  35. stack_elem *array = NULL;
  36. array = (stack_elem*)calloc((s->size), sizeof(struct _n_node));
  37. for (int i = ((s->size)-1); i >= 0; --i) {
  38. array[i]=stack_top(s);
  39. s->first=s->first->next;
  40. }
  41. return array;
  42. }

首先,无需为数组分配与sizeof(struct _n_node)相等的元素大小,因为您正在存储stack_elem类型的元素

  1. array[i]=stack_top(s);

这是int类型的别名

  1. typedef int stack_elem;

第二个问题是由于这个语句

  1. s->first=s->first->next;

数据成员first被更改,指向分配的节点的指针丢失,但栈中的节点本身未被删除,导致大量内存泄漏。您需要使用辅助指针变量来遍历栈。

例如,函数可以如下所示:

  1. stack_elem * stack_to_array( stack s )
  2. {
  3. stack_elem *array = NULL;
  4. if ( !stack_is_empty( s ) )
  5. {
  6. array = calloc( s->size, sizeof( stack_elem ) );
  7. if ( array != NULL )
  8. {
  9. node current = s->first;
  10. for ( int i = s->size ; i-- != 0; )
  11. {
  12. array[i] = current->elem;
  13. current = current->next;
  14. }
  15. }
  16. }
  17. return array;
  18. }
英文:

The problem exists due to this invalid function

  1. stack_elem *stack_to_array(stack s) {
  2. stack_elem *array = NULL;
  3. array = (stack_elem*)calloc((s-&gt;size), sizeof(struct _n_node));
  4. for (int i = ((s-&gt;size)-1); i &gt;= 0; --i) {
  5. array[i]=stack_top(s);
  6. s-&gt;first=s-&gt;first-&gt;next;
  7. }
  8. return array;
  9. }

For starters there is no need to allocate the array with the element size equal to sizeof(struct _n_node) because you are storing in the array elements

  1. array[i]=stack_top(s);

of the type stack_elem that is an alias of the type int

  1. typedef int stack_elem;

The second problem is that due to this statement

  1. s-&gt;first=s-&gt;first-&gt;next;

the data member first is changed and pointers to allocated nodes are lost but nodes themselves in the stack are not deleted that results in numerous memory leaks. You need to use an auxiliary pointer variable to traverse the stack.

For example the function can look the following way

  1. stack_elem * stack_to_array( stack s )
  2. {
  3. stack_elem *array = NULL;
  4. if ( !stack_is_empty( s ) )
  5. {
  6. array = calloc( s-&gt;size, sizeof( stack_elem ) );
  7. if ( array != NULL )
  8. {
  9. node current = s-&gt;first;
  10. for ( int i = s-&gt;size ; i-- != 0; )
  11. {
  12. array[i] = current-&gt;elem;
  13. current = current-&gt;next;
  14. }
  15. }
  16. }
  17. return array;
  18. }

huangapple
  • 本文由 发表于 2023年6月1日 06:16:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76377626.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定