ошибка выделения памяти в C - PullRequest
5 голосов
/ 10 мая 2019

Я некоторое время работал над следующим кодом, и возникла проблема, когда я пытался выделить / освободить память для структуры и ее элементов.Любое понимание проблемы будет высоко оценено, спасибо.Глядя на сообщение об ошибке, я полагаю, что проблема заключается в том, что я пытался освободить элемент, для которого у меня не было должным образом выделенной памяти, но для меня это не очевидно при просмотре кода.Я также попробовал код, в котором я не выделил память для каждого элемента структуры по отдельности, но это не сработало.

typedef struct {
  char *cnet;
  char *email;
  char *fname;
  char *lname;
  char *tel;
} vcard;

vcard *vcard_new(char *cnet, char *email, char *fname, char *lname, char *tel)
{
  vcard* new = (vcard*)malloc(sizeof(vcard));
  printf("%lu\n", sizeof(new->tel) );
  new->cnet = malloc(sizeof(new->cnet));
  new->email = malloc(sizeof(new->email));
  new->fname = malloc(sizeof(new->fname));
  new->lname = malloc(sizeof(new->lname));
  new->tel = malloc(sizeof(new->tel));
  new->cnet = cnet;
  new->email = email;
  new->fname = fname;
  new->lname = lname;
  new->tel = tel;
  return new;
}

/* vcard_free : free vcard and the strings it points to
 */
void vcard_free(vcard *c)
{
  free(c->cnet);
  free(c->email);
  free(c->fname);
  free(c->lname);
  free(c->tel);
  free(c);
  return;
}

Ответы [ 3 ]

6 голосов
/ 10 мая 2019

Ваше распределение памяти ошибочно. Вот несколько указателей.

  1. Вы выделяете память только для одного char *, что не соответствует назначению.

    • Меньшее выделение памяти, возможность переполнения границы.
  2. Затем вы перезаписываете выделенную память, присваивая параметры тем же переменным, которые содержали указатель на выделенную память.

    • Вы в конечном итоге вызываете утечку памяти.
  3. Вы пытаетесь освободить указатели, которые не возвращаются malloc() и семьей.
  4. Вы использовали неверный спецификатор формата в printf()
    • sizeof дает результат типа size_t, вы должны использовать %zu, чтобы напечатать результат.

Решения:

  1. Выделите достаточно памяти для хранения ожидаемого содержимого, как в предопределенных размерах

     #define CNETSIZ 32
     #define EMAILSIZ 64
     . . . . . 
     new->cnet = malloc(CNETSIZ);
     new->email = malloc(EMAILSIZ);
    

    или, в зависимости от длины входной строки, например

     new->cnet = malloc(strlen(cnet)+1);  //+1 for the space to null-terminator
    
  2. Внутри функции vcard_new() используйте strcpy(), чтобы скопировать содержимое из параметров функции, например

    strcpy(new->cnet, cnet);
    strcpy(new->email, email);
    
4 голосов
/ 10 мая 2019

Вы просто выделяете достаточно памяти для хранения другой char* вместо фактической строки.И затем вы перезаписываете указатель переданным указателем.Позже вы попытаетесь освободить этот указатель, что означает, что он попытается освободить память, из которой вы взяли указатель и передали его функции.Вместо этого вы должны сделать следующее:

vcard *vcard_new(char *cnet, char *email, char *fname, char *lname, char *tel)
{
  vcard* new = (vcard*)malloc(sizeof(vcard));
  new->cnet = malloc(strlen(cnet)+1);
  strcpy(new->cnet, cnet);
  ...
}

Или, если strdup доступно в вашей системе:

vcard *vcard_new(char *cnet, char *email, char *fname, char *lname, char *tel)
{
  vcard* new = (vcard*)malloc(sizeof(vcard));
  new->cnet = strdup(cnet);
  ...
}
3 голосов
/ 10 мая 2019

Используя new->cnet = malloc(sizeof(new->cnet)), вы выделяете объем памяти для строки cnet, равный размеру указателя, а не фактической длине строки.

...