Динамическое распределение памяти для структур в c - PullRequest
0 голосов
/ 23 мая 2018

Я пытаюсь инициализировать структуру, выделяя ей память и ее элементы-указатели, используя malloc:

typedef struct {
    char *name;
    prob_t *prob;
} name_t;

Я понимаю, что мне нужно выделять память для указателей отдельно после инициализации структуры:

name_t
*init_name_dict() {
    name_t *name_dict;
    name_dict = (name_t*)malloc(MAX_LINES*sizeof(*name_dict));
    name_dict->name = (char*)malloc(MAX_LEN*sizeof(*name_dict->name));
    name_dict->prob = (prob_t*)malloc(MAX_PROB*sizeof(*name_dict->prob));
    return name_dict;
}

Но когда я это делаю, он выделяет память для структуры, а не для одного из ее указателей-членов (они просто указывают на мусор).

Что я делаю неправильно?Спасибо

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

Как объяснено здесь , malloc не "чистит" память, которая затем может быть заполнена мусором (поскольку, например, та же самая память была возвращена другим вызовом malloc(), использованныма затем free()).Три классических решения:

  • Живи с этим.Установите вручную все элементы struct (если вы используете malloc для выделения struct) перед использованием struct (или вообще установите для всей полученной памяти желаемое значение)
  • Используйте memset для обнуления всей памяти перед ее использованием
  • Используйте calloc вместо malloc (обратите внимание, что у него немного другая подпись).calloc похож на malloc + memset.В качестве примера:

name_t *init_name_dict() {
    name_t *name_dict;
    name_dict = calloc(MAX_LINES, sizeof(*name_dict));
    name_dict->name = calloc(MAX_LEN, sizeof(*name_dict->name));
    name_dict->prob = calloc(MAX_PROB, sizeof(*name_dict->prob));
    return name_dict;
}

В качестве идентификатора, в C вам не нужно / не следует приводить указатель, возвращаемый malloc / calloc ( но если на самом деле вы используете компилятор C ++, вы должны привести его ... ).

0 голосов
/ 23 мая 2018

Если вы хотите очистить память (в отличие от памяти с мусором в ней), вам нужно calloc вместо malloc, но это тривиально.

Вы больше проблем:

1) no error checking
2) possibly needless malloc calls
3) you're allocating MAX_LINES of theses name_t structure but initializing 
  only one of them

Если поля .name и .prob не будут перераспределены, вам следует изменить определение name_t на

typedef struct { char name[MAX_LEN]; prob_t prob[MAX_PROB]; } name_t;

и выделить все имена MAX_LINES__ за один раз: calloc(MAX_LINES, sizeof(name_t)).

Если вам нужна исходная структура name_t, то я бы имел инициализатор для одного:

int init_name_dict (name_t  *this)
{
    if(0==(this->name=calloc(MAX_LEN, sizeof *this->name))) return -1;
    if(0==(this->prob=calloc(MAX_PROB, sizeof *this->prob))){ free(this->name); return -1; }
    return 0;
}

деструктор для нее

void destroy_name_dict(name_t *this) { free(this->name); free(this->prob); }

и затем инициализирующий распределитель для всего массива:

name_t* new_name_dicts(void)
{
    name_t *r = malloc(MAX_LINES*sizeof *r);
    if(!r) return r;
    int i;
    for(i=0; i<MAX_LINES; i++)
        if(0>init_name_dict(&r[i])) goto fail;
    return r;
    fail:
        for(--i; i>=0; --i)
            destructor_name_dict(&r[i]);
    return NULL;
}

(В основном, что будет означать векторный конструктор C ++, который выбирает конструктор для типа ячейки.)

0 голосов
/ 23 мая 2018

Структура

typedef struct {
    char *name;
    prob_t *prob;
} name_t;

имеет два указателя в качестве членов.Таким образом, на 32-битной ОС sizeof(name_t) составляет 8 байтов.Динамическое создание экземпляра name_t struct

name_t *name_dict = (name_t*)malloc(sizeof(name_dict));

выделяет только 8 байтов для хранения двух указателей.Как сказал Ксанатос, выделенная память является мусором, а указатели будут указывать на случайные места.Вы можете использовать calloc() при выделении name_dict или вручную обнулить их name_dict->name = NULL;name_dict->prob = NULL;.Вы также можете не беспокоиться о содержании указателей и в следующей строке кода выделить память для членов

name_dict->name = (char*)malloc(MAX_LEN*sizeof(char));
name_dict->prob = (prob_t*)malloc(sizeof(prob_t));

Вы также можете проверить, правильно ли выделена память, и оба указателя не указывают на NULL.

Подводя итог, правильно написанный метод init_name_dict ()

name_t * init_name_dict() 
{
  name_t *name_dict = (name_t*)malloc(sizeof(name_t));
  if  (name_dict != NULL)
  {
        name_dict->name = (char*)malloc(MAX_LEN*sizeof(char)));
        name_dict->prob = (prob_t*)malloc(sizeof(prob_t));
  }
  return name_dict;
 }

Ошибки в вашем коде были

  • MAX_LINES здесь (предположим, что вы хотите создать здесь только одну структуру)

    name_dict = (name_t*)malloc(MAX_LINES*sizeof(*name_dict));

  • MAX_PROB здесь (предположим, что вы хотите создать здесь только одну структуру)

    name_dict->prob = (prob_t*)malloc(MAX_PROB*sizeof(*name_dict->prob));

...