Deallocating memory for array within a linked chain struct

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

Deallocating memory for array within a linked chain struct

问题

我正在尝试释放链接链中不同结构体使用的内存。dumpGroupingOrder() 函数应该释放所使用的内存,然而,一旦使用它,整个程序就停止运行。没有它,程序仍然工作,尽管存在内存泄漏,参见下面valgrind的输出:

LEAK SUMMARY:
definitely lost: 48 bytes in 1 blocks
indirectly lost: 328 bytes in 11 blocks

有了它,就没有内存泄漏,但我却得到一个 double free or corruption (out) 错误消息,并且从valgrind获得以下错误消息:

Invalid free() / delete / delete[] / realloc()
   at 0x48399AB: free (vg_replace_malloc.c:538)
   by 0x10929A: dumpGroupingOrder (code-stack.c:54)
   by 0x10952F: main (code-stack.c:88)
   Address 0x1fff0000b0 is on thread 1's stack
   in frame #2, created by main (code-stack.c:74)

以下是用作MWE的整个代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

struct groupingOrder {
  int *taxa;
  size_t groupeSize;
  long double distance;
  struct groupingOrder* next;
};

void addGroup(struct groupingOrder* HEAD, int *groupe, size_t groupeSize, long double distance) {
  struct groupingOrder* temp = HEAD;
  // 移动最后一个单元结构
  while(temp->next != NULL) {
    temp = temp->next;
  }
  // 为单元结构分配空间
  struct groupingOrder* nouveau = malloc(sizeof(struct groupingOrder));
  nouveau->distance = distance;
  nouveau->groupeSize = groupeSize;
  // 为要存储的分类单元列表分配变量空间
  nouveau->taxa = malloc(groupeSize * sizeof(int));
  for(int i = 0; i < groupeSize; i++) {
    nouveau->taxa[i] = groupe[i];
  }
  // 将新的单元结构链接到前一个单元结构
  temp->next = nouveau;
  // 指定NULL指针以标记最后一个单元
  nouveau->next = NULL;
}

void dumpGroupingOrder(struct groupingOrder* HEAD) {
  struct groupingOrder* temp = HEAD;
  while(temp != NULL) {
    // 复制当前单元的地址
    struct groupingOrder* dumpTarget = temp;
    // 在释放当前单元之前,存储下一个单元的地址
    temp = temp->next;
    // 释放当前单元及其分配的所有变量
    if(dumpTarget->taxa != NULL) {
      free(dumpTarget->taxa);
      printf("#");
    }
    free(dumpTarget);
    printf("* ");
  }
}

void showGroupingOrder(struct groupingOrder* HEAD) {
  struct groupingOrder* temp = HEAD;
  while(temp->next != NULL) {
    temp = temp->next;
    for(int i = 0; i < temp->groupeSize; i++) {
      printf(" %d", temp->taxa[i]);
    }
    printf(" %Lf\n", temp->distance);
  }
}

int main() {
  size_t groupeSize[6] = { 2,2,4,2,5,7 };
  int groupes[][7] = { {2,3}, {5,1}, {2,3,5,1}, {7,4}, {2,3,5,1,6}, {2,3,5,1,6,7,4} };
  struct groupingOrder HEAD = { .next = NULL };
  for(int i = 0; i < 6; i++){
    addGroup(&HEAD, groupes[i], groupeSize[i], 0.0003);
  }
  showGroupingOrder(&HEAD);
  printf("\n\n");
  dumpGroupingOrder(&HEAD);
  return 0;
}
英文:

I am trying to deallocate the memory used by different struct that are part of a linked chain.
The dumpGroupingOrder() function is supposed to deallocate the memory used, however the whole program ceases to function once it is used. Without it the program works even though there are memory leaks, see the output of valgrind below:

LEAK SUMMARY:
definitely lost: 48 bytes in 1 blocks
indirectly lost: 328 bytes in 11 blocks

With it there are no memory leaks, but I get a double free or corruption (out) error message instead and the following error message from valgrind:

Invalid free() / delete / delete[] / realloc()
at 0x48399AB: free (vg_replace_malloc.c:538)
by 0x10929A: dumpGroupingOrder (code-stack.c:54)
by 0x10952F: main (code-stack.c:88)
Address 0x1fff0000b0 is on thread 1&#39;s stack
in frame #2, created by main (code-stack.c:74)

Below the entire code used as a MWE:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;math.h&gt;
struct groupingOrder {
int *taxa;
size_t groupeSize;
long double distance;
struct groupingOrder* next;
};
void addGroup( struct groupingOrder* HEAD, int * groupe, size_t groupeSize, long double distance ) {
struct groupingOrder* temp = HEAD;
// Moving the last unit structure
while( temp-&gt;next != NULL ) {
temp = temp-&gt;next;
}
// Allocating space for the unit structure
struct groupingOrder* nouveau = malloc( sizeof( struct groupingOrder ) );
nouveau-&gt;distance = distance;
nouveau-&gt;groupeSize = groupeSize;
// Allocating variable space for the list of taxa to be stored
nouveau-&gt;taxa = malloc( groupeSize * sizeof( int ) );
for( int i = 0; i &lt; groupeSize; i++) {
nouveau-&gt;taxa[i] = groupe[i];
}
// Linking the new unit structure to the previous one
temp-&gt;next = nouveau;
// Specifying the NULL pointer to label the last unit
nouveau-&gt;next = NULL;
}
void dumpGroupingOrder( struct groupingOrder* HEAD ) {
struct groupingOrder* temp = HEAD;
while( temp != NULL ) {
// Copying the address of the current unit
struct groupingOrder* dumpTarget = temp;
// Storing the address of the next unit before dumping the
//  current one.
temp = temp-&gt;next;
// Dumping the current unit and all its allocated variables
if( dumpTarget-&gt;taxa != NULL ) {
free( dumpTarget-&gt;taxa );
printf( &quot; #&quot; );
}
free( dumpTarget );
printf( &quot;* &quot; );
}
}
void showGroupingOrder( struct groupingOrder* HEAD ) {
struct groupingOrder* temp = HEAD;
while( temp-&gt;next != NULL ) {
temp = temp-&gt;next;
for( int i = 0; i &lt; temp-&gt;groupeSize; i++) {
printf( &quot; %d&quot;, temp-&gt;taxa[i] );
}
printf( &quot; %Lf\n&quot;, temp-&gt;distance );
}
}
int main() {
size_t groupeSize[6] = { 2,2,4,2,5,7 };
int groupes[][7] = { {2,3}, {5,1}, {2,3,5,1}, {7,4}, {2,3,5,1,6}, {2,3,5,1,6,7,4} };
struct groupingOrder HEAD = { .next = NULL };
for( int i = 0; i &lt; 6; i++ ){
addGroup( &amp;HEAD, groupes[i], groupeSize[i], 0.0003 );
}
showGroupingOrder( &amp;HEAD );
printf( &quot;\n\n&quot; );
dumpGroupingOrder( &amp;HEAD );
return 0;
}

答案1

得分: 2

Your function dumpGroupingOrder tries to free everything in the list, including the HEAD.

On the other hand, what is passed from the function main as HEAD is a pointer to a local variable, not a pointer returned from malloc() family.

You mustn't free what are not NULL nor things returned from malloc() family.

You should change

struct groupingOrder* temp = HEAD;

in the function dumpGroupingOrder to

struct groupingOrder* temp = HEAD->next;

to avoid freeing HEAD.

英文:

Your function dumpGroupingOrder tries to free everything in the list, including the HEAD.

On the other hand, what is passed from the function main as HEAD is a pointer to a local variable, not a pointer returned from malloc() family.

You mustn't free what are not NULL nor things returned from malloc() family.

You should change

struct groupingOrder* temp = HEAD;

in the function dumpGroupingOrder to

struct groupingOrder* temp = HEAD-&gt;next;

to avoid freeing HEAD.

答案2

得分: 2

如前面的回答中已经指出的,问题在于您的链表的头节点没有通过malloc分配内存。因此,您不能调用free释放该节点。

不过,与其他回答不同的是,我不建议在释放内存时跳过头节点来解决问题,而是建议重新构建您的程序,以使所有节点(包括头节点)都能平等对待,从而也为头节点分配内存使用malloc

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

struct groupingOrder {
    int *taxa;
    size_t groupeSize;
    long double distance;
    struct groupingOrder* next;
};

void addGroup(struct groupingOrder** HEAD, int* groupe, size_t groupeSize, long double distance) {
    struct groupingOrder** temp = HEAD;
    while (*temp != NULL) {
        temp = &(*temp)->next;
    }
    
    struct groupingOrder* nouveau = malloc(sizeof(struct groupingOrder));
    nouveau->distance = distance;
    nouveau->groupeSize = groupeSize;
    nouveau->taxa = malloc(groupeSize * sizeof(int));
    for (int i = 0; i < groupeSize; i++) {
        nouveau->taxa[i] = groupe[i];
    }
    nouveau->next = NULL;
    *temp = nouveau;
}

void dumpGroupingOrder(struct groupingOrder** HEAD) {
    struct groupingOrder* temp = *HEAD;
    while (temp != NULL) {
        struct groupingOrder* dumpTarget = temp;
        temp = temp->next;
        if (dumpTarget->taxa != NULL) {
            free(dumpTarget->taxa);
            printf(" #");
        }
        free(dumpTarget);
        printf("* ");
    }
    *HEAD = NULL;
}

void showGroupingOrder(struct groupingOrder* HEAD) {
    for (struct groupingOrder* temp = HEAD; temp != NULL; temp = temp->next) {
        for (int i = 0; i < temp->groupeSize; i++) {
            printf(" %d", temp->taxa[i]);
        }
        printf(" %Lf\n", temp->distance);
    }
}

int main() {
    size_t groupeSize[6] = {2, 2, 4, 2, 5, 7};
    int groupes[][7] = {{2, 3}, {5, 1}, {2, 3, 5, 1}, {7, 4}, {2, 3, 5, 1, 6}, {2, 3, 5, 1, 6, 7, 4}};

    struct groupingOrder* HEAD = NULL;

    for (int i = 0; i < 6; i++) {
        addGroup(&HEAD, groupes[i], groupeSize[i], 0.0003);
    }

    showGroupingOrder(HEAD);
    printf("\n\n");
    dumpGroupingOrder(&HEAD);

    return 0;
}

这个程序的输出如下:

 2 3 0.000300
5 1 0.000300
2 3 5 1 0.000300
7 4 0.000300
2 3 5 1 6 0.000300
2 3 5 1 6 7 4 0.000300
#*  #*  #*  #*  #*  #* 
英文:

As already pointed out in the other answer, the problem is that the head node of your linked list was not allocated by malloc. Therefore, you are not allowed to call free on that node.

However, in contrast to the other answer, I do not recommend that you fix the problem by leaving out the head node when freeing the memory, but rather to restructure your program so that all nodes (including the head node) are treated equally, so that also the memory for the head node gets allocated by malloc:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;math.h&gt;
struct groupingOrder {
int *taxa;
size_t groupeSize;
long double distance;
struct groupingOrder* next;
};
void addGroup( struct groupingOrder** HEAD, int * groupe, size_t groupeSize, long double distance ) {
struct groupingOrder** temp = HEAD;
// Make &quot;temp&quot; point to the &quot;next&quot; member of the last node of
// the list, or if the list is empty, make &quot;temp&quot; point to
// the pointer to the head node (which has the value NULL).
while( (*temp) != NULL ) {
temp = &amp;(*temp)-&gt;next;
}
// Allocating space for the unit structure
struct groupingOrder* nouveau = malloc( sizeof( struct groupingOrder ) );
nouveau-&gt;distance = distance;
nouveau-&gt;groupeSize = groupeSize;
// Allocating variable space for the list of taxa to be stored
nouveau-&gt;taxa = malloc( groupeSize * sizeof( int ) );
for( int i = 0; i &lt; groupeSize; i++) {
nouveau-&gt;taxa[i] = groupe[i];
}
// Specifying the NULL pointer to label the last unit
nouveau-&gt;next = NULL;
// Linking the new unit structure to the previous one
*temp = nouveau;
}
void dumpGroupingOrder( struct groupingOrder** HEAD ) {
struct groupingOrder* temp = *HEAD;
while( temp != NULL ) {
// Copying the address of the current unit
struct groupingOrder* dumpTarget = temp;
// Storing the address of the next unit before dumping the
//  current one.
temp = temp-&gt;next;
// Dumping the current unit and all its allocated variables
if ( dumpTarget-&gt;taxa != NULL ) {
free( dumpTarget-&gt;taxa );
printf( &quot; #&quot; );
}
free( dumpTarget );
printf( &quot;* &quot; );
}
// Mark linked list as empty
*HEAD = NULL;
}
void showGroupingOrder( struct groupingOrder* HEAD ) {
for ( struct groupingOrder* temp = HEAD; temp != NULL; temp = temp-&gt;next ) {
for( int i = 0; i &lt; temp-&gt;groupeSize; i++) {
printf( &quot; %d&quot;, temp-&gt;taxa[i] );
}
printf( &quot; %Lf\n&quot;, temp-&gt;distance );
}
}
int main() {
size_t groupeSize[6] = { 2,2,4,2,5,7 };
int groupes[][7] = { {2,3}, {5,1}, {2,3,5,1}, {7,4}, {2,3,5,1,6}, {2,3,5,1,6,7,4} };
struct groupingOrder *HEAD = NULL;
for ( int i = 0; i &lt; 6; i++ ) {
addGroup( &amp;HEAD, groupes[i], groupeSize[i], 0.0003 );
}
showGroupingOrder( HEAD );
printf( &quot;\n\n&quot; );
dumpGroupingOrder( &amp;HEAD );
return 0;
}

It was necessary for me to modify the function main and addGroup. I also modified the other two functions, but these changes were not necessary.

This program has the following output:

 2 3 0.000300
5 1 0.000300
2 3 5 1 0.000300
7 4 0.000300
2 3 5 1 6 0.000300
2 3 5 1 6 7 4 0.000300
#*  #*  #*  #*  #*  #* 

huangapple
  • 本文由 发表于 2023年3月3日 23:37:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75629089.html
匿名

发表评论

匿名网友

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

确定