C бесплатный символ * размещается в куче - PullRequest
5 голосов
/ 24 октября 2010

Есть ли утечка памяти в следующем примере кода, поскольку я выделил память в куче для имени, которое не было освобождено?Если я добавлю бесплатно (человек-> имя);перед свободным (человек);Затем я получаю ошибку во время выполнения в VS "CRT обнаружил, что приложение записало в память после завершения буфера кучи".

header.h:

#ifndef HEADER
#define HEADER

typedef struct person {
 char *name;
} Person;

#endif

source.c:

#include <stdio.h>
#include <stdlib.h>
#include "header.h"

#define BUFFERSIZE 500

int main (int argc, char* argv[]){
 Person *person = NULL;
 char buffer[BUFFERSIZE];
 printf("Enter name\n");
 fgets(buffer, BUFFERSIZE, stdin);
 {
  char *name; 
  person = malloc(sizeof(Person));
  name = malloc(strlen(buffer));
  strcpy (name,buffer);
  person->name = name;
 }
 free(person); 
 return 0;
}

Спасибо, Роб

Ответы [ 4 ]

10 голосов
/ 24 октября 2010

strlen не учитывает нулевой терминатор, который добавляет strcpy, вам нужно "malloc (strlen (buffer) +1)" *

9 голосов
/ 24 октября 2010

Да, код имеет утечку памяти.

Виновным является: name = malloc(strlen(buffer));, который должен быть
name = malloc(strlen(buffer)+1); на счет \0.

Теперь вы сможете освободить person->name.

3 голосов
/ 24 октября 2010

Да. Утечка памяти.

Вы выделяете буфер имен:

name = malloc(strlen(buffer));

и никогда не освобождай его. Затем, когда вы освобождаете Person,

free(person); 

вы теряете свой последний указатель на этот буфер, поэтому вы можете никогда освобождать его.

Сообщение об ошибке, которое вы получаете, является отдельной проблемой, связанной с тем, что длина буфера имен, который вы выделяете, недостаточна для включения нулевого завершения строки, которую вы пытаетесь скопировать в нее.

1 голос
/ 24 октября 2010

name никогда не освобождается, поэтому происходит утечка.

Сложные структуры, выделенные в куче, подобные этим, часто лучше всего обрабатываются при переходе на C ++ или (если это невозможно) путем обертывания памятиуправление в пользовательских функциях создания / уничтожения / манипуляции:

Person *CreatePerson(void) {
    /* you can use calloc() here, of course */
    Person *result = malloc(sizeof(Person));
    if (result) {
        memset(result, 0, sizeof(Person));
    }
    return result;
}

void DestroyPerson(Person *p) {
    if (p) {
        free(p->name);
        free(p);
    }
}

void SetPersonName(Person *p, const char *name) {
    if (p) {
        if (p->name) {
            free(p->name);
            p->name = NULL;
        }

        if (name) {
            size_t len = strlen(name);
            p->name = malloc(len + 1);
            if (p->name) {
                strncpy(p->name, name, len);
                p->name[len] = 0;
            }
        }
    }
}

const char *GetPersonName(const Person *p) {
    if (p)
        return p->name;
    return NULL;
}

Однако, как вы можете видеть по количеству используемого кода, C ++ часто является лучшим выбором:

class Person {
    private: std::string name;

    public: const std::string& getName(void) const {
        return this->name;
    }

    public: void setName(const std::string& newName) {
        this->name = newName;
    }
};

Гораздо короче, чище и яснее!

...