C динамически распределяет массив массива и его компоненты - PullRequest
0 голосов
/ 27 ноября 2018

Каков правильный подход для динамического выделения массива структуры и его компонентов в C?Мне удалось сделать что-то, что работает, но я немного скептически отношусь, если это правильно.У меня есть следующий код:
Это мой массив структуры, который мне нужно динамически распределить:

typedef struct
{
    char *wrong;
    char *right;
}Dictionary;

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

Dictionary *init_Dictionary(int nr_elem)
{
    Dictionary *dict;
    dict = malloc(nr_elem*sizeof(Dictionary));
    for(int i=0; i<nr_elem; i++)
    {
        char wrong[101],right[101];
        scanf("%s%s",wrong,right);
        dict[i].wrong = malloc(strlen(wrong)*sizeof(char));
        dict[i].right = malloc(strlen(right)*sizeof(char));
        strcpy(dict[i].wrong,wrong);
        strcpy(dict[i].right,right);
    }
    return dict;
}

Тогда в моей основной функции у меня есть это:

    int nr_elem;
    scanf("%d",&nr_elem);
    Dictionary *dict;
    dict = init_Dictionary(nr_elem);

Кроме того, когда я закончу работу со структурой, как мне освободить использованную память?
РЕДАКТИРОВАТЬ Спасибо всем за быстрые и глубокие ответы!

Ответы [ 3 ]

0 голосов
/ 27 ноября 2018

В вашей реализации есть ошибка: strlen(s) не считает завершающий 0-символ, поэтому, несмотря на то, что один тест может работать успешно, на самом деле это UB.strdup может сделать работу за вас;если у вас нет стандартной библиотеки, просто добавьте 1 при выделении памяти для строковых копий.Или даже лучше: посчитайте длину строки один раз, затем используйте это значение для выделения достаточного количества байтов и копирования содержимого с помощью memcpy.

В противном случае ваш алгоритм весьма полезен (при условии, что массив пар строк действительно то, что вам нужно(без дополнительной структуры, такой как поисковый индекс или что-либо еще).

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

void destroy(Dictionary *dict, size_t nr_elem) {
    for(size_t i = 0; i < nr_elem; ++i) {
        free(dict[i].wrong);
        free(dict[i].right);
    }
    free(dict);
}
0 голосов
/ 27 ноября 2018

Для каждого выделения вам нужно выделить еще одно местоположение, чтобы учесть \0 (терминатор NULL) в конце строки.

dict[i].wrong = malloc(strlen(wrong)*sizeof(char) +1 );
dict[i].right = malloc(strlen(right)*sizeof(char) +1);

Чтобы освободить, сначала необходимо освободить все указатели right и wrong в массиве, а затем освободить основной массив dict.При желании вы можете обнулять указатели после освобождения.

Dictionary* freeDict(Dictionary *dict, int nr_elem)
{
    for (int i=0; i<nr_elem; i++)
    {
        free(dict->wrong);
        free(dict->right);
        dict->wrong = NULL;
        dict->right = NULL;
    }
    free (dict);
    dict = NULL;
    return dict;
}

//To call.
dict = free(dict, nr_elem);
0 голосов
/ 27 ноября 2018

Дизайн программы не очень хороший, вы должны отделить пользовательский интерфейс от алгоритмов.Вместо этого вы должны сначала принять пользовательский ввод, затем сохранить его в 2 строки и передать строки в качестве параметров в init_Dictionary.

Что касается распределения, то оно почти правильное.Но вы забыли выделить место для нулевого терминатора, оно должно быть следующим:

dict[i].wrong = malloc(strlen(wrong)+1);
dict[i].right = malloc(strlen(right)+1);

Умножение на sizeof(char) не имеет смысла, поскольку определение sizeof(char) всегда 1 во всех системах.

В приложении производственного качества вы всегда должны проверять результат каждого malloc, а затем обрабатывать ошибки.

Вы освобождаете память так же, как вы ее выделили, но в противоположном направлении.Порядок, так как сам dict должен быть действительным до тех пор, пока вы не освободите его членов:

for(int i=0; i<nr_elem; i++)
{
  free(dict[i].wrong);
  free(dict[i].right);
}
free(dict);

Как правило, каждый вызов malloc должен совпадать с вызовом free.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...