释放链表中的char指针时出现C内存泄漏

时间:2017-09-29 10:33:55

标签: c string pointers memory-leaks linked-list

我有一个代码创建一个可以是不同类型的值的链接列表,例如弦乐或双打。但是,在程序结束时,在释放链表之后,由于我在其中添加字符串的方式,我留下了内存泄漏。我的代码如下:

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

// compile with: gcc test_list.c -o test_list
// to check memory leaks run:
// >> valgrind --leak-check=full -v ./test_list

typedef enum tagParamType {
  TYPE_double_t = 0,
  TYPE_string_t
} ParamType;

size_t TypeSize[2] = {
  sizeof(double),
  sizeof(const char*)
};

typedef struct tagParam {
  char name[1024];       /* Parameter name */
  void *value;           /* Parameter value */
  ParamType type;        /* type of parameter */
  struct tagParam *next;
} Param;

typedef struct tagParameters {
  Param *head;
} Parameters;

void AddParam( Parameters *pars, const char *name, const void *value, ParamType type );
void RemoveParameters( Parameters *pars );
Parameters *CreateParameters( );
void PrintParameters( Parameters *pars );

void AddParam( Parameters *pars, const char *name, const void *value, ParamType type ){
  Param *par = NULL;
  par = malloc(sizeof(Param));
  memset(par, 0, sizeof(Param)); // set everything to 0

  par->value = (void *)malloc( TypeSize[type] );
  memcpy( par->value, value, TypeSize[type] );
  strncpy( par->name, name, 1024 );
  par->type = type;

  par->next = pars->head;
  pars->head = par;
}

void RemoveParameters( Parameters *pars ){
  Param *this, *next = NULL;
  this = pars->head;

  if ( this ) { next = this->next; }

  while ( this ){
    free( this->value );
    free( this );
    this = next;
    if ( this ) { next = this->next; }
  }

  pars->head = NULL;
}

Parameters *CreateParameters( ){
  Parameters *pars = calloc(sizeof(*pars), 1);

  /* add a string */
  const char *svalue = strdup("Matthew");
  AddParam( pars, "First name", &svalue, TYPE_string_t );

  /* add a double */
  double dvalue = 0.1;
  AddParam( pars, "A number", &dvalue, TYPE_double_t );

  return pars;
}

void PrintParameters( Parameters *pars ){
  Param *this, *next = NULL;
  this = pars->head;
  if ( this ) { next = this->next; }
  while ( this ){
    if ( this->type == TYPE_double_t ) { fprintf( stdout, "%s is %lf\n", this->name, *(double*)this->value ); }
    else if ( this->type == TYPE_string_t ) { fprintf( stdout, "%s is %s\n", this->name, *(char**)this->value ); }
    this = next;
    if ( this ) { next = this->next; }
  }
}

int main (){
  Parameters *pars = CreateParameters( );
  PrintParameters( pars );
  RemoveParameters( pars );

  return 0;
}

我可以用不同的方式将字符串参数添加到链表中,还是以不同的方式释放它们,这样可以避免内存泄漏?释放svalue函数中的CreateParameters()字符串会导致它从链接列表中删除,尽管变量为memcpy

很抱歉,如果这是重复的,答案可以在其他地方找到。

修复泄漏的代码的编辑

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

// compile with: gcc -g test_list.c -o test_list
// to check memory leaks run:
// >> valgrind --leak-check=full -v ./test_list

typedef enum tagParamType {
  TYPE_double_t = 0,
  TYPE_string_t
} ParamType;

size_t TypeSize[2] = {
  sizeof(double),
  sizeof(const char*)
};

typedef struct tagParam {
  char name[1024];       /* Parameter name */
  void *value;           /* Parameter value */
  ParamType type;        /* type of parameter */
  struct tagParam *next;
} Param;

typedef struct tagParameters {
  Param *head;
} Parameters;

void AddParam( Parameters *pars, const char *name, const void *value, ParamType type );
void RemoveParameters( Parameters *pars );
Parameters *CreateParameters( );
void PrintParameters( Parameters *pars );

void AddParam( Parameters *pars, const char *name, const void *value, ParamType type ){
  Param *par = NULL;
  par = malloc(sizeof(Param));
  memset(par, 0, sizeof(Param)); // set everything to 0

  if ( type == TYPE_string_t ){
    par->value = (void *)strndup((const char*)value, TypeSize[type]);
  }
  else{
    par->value = (void *)malloc( TypeSize[type] );
    memcpy( par->value, value, TypeSize[type] );
  }
  strncpy( par->name, name, 1024 );
  par->type = type;

  par->next = pars->head;
  pars->head = par;
}

void RemoveParameters( Parameters *pars ){
  Param *this, *next = NULL;
  for ( this = pars->head, next = this->next ; this; ){
    free( this->value );
    free( this );
    this = next;
    if ( this ){ next = this->next; }
  }

  pars->head = NULL;
}

Parameters *CreateParameters( ){
  Parameters *pars = calloc(sizeof(*pars), 1);

  /* add a string */
  const char *svalue = strdup("Matthew");
  AddParam( pars, "First name", (const void*)svalue, TYPE_string_t );

  /* add a double */
  double dvalue = 0.1;
  AddParam( pars, "A number", &dvalue, TYPE_double_t );

  free((char*)svalue);
  return pars;
}

void PrintParameters( Parameters *pars ){
  Param *this, *next = NULL;
  for ( this = pars->head, next = this->next ; this; ){
    if ( this->type == TYPE_double_t ) { fprintf( stdout, "%s is %lf\n", this->name, *(double*)this->value ); }
    else if ( this->type == TYPE_string_t ) { fprintf( stdout, "%s is %s\n", this->name, (char*)this->value ); }
    this = next;
    if ( this ){ next = this->next; }
  }
}

int main (){
  Parameters *pars = CreateParameters( );
  PrintParameters( pars );
  RemoveParameters( pars );
  free( pars );

  return 0;
}

0 个答案:

没有答案