Как правильно выделить память в этом коде? - PullRequest
0 голосов
/ 03 мая 2019

Я работаю над домашним заданием на Си, и мне довольно сложно определить, какая память не была выделена.

Я пытался разместить функцию free () в разных местах своего кода, просто чтобы проверить, сработает ли она или нет, но ни одна из попыток пока не принесла результатов.

это структура и используемые для нее функции; все функции ниже находятся внутри одного файла с именем state.c - stateAdd вызывает stateNodeCreate -

typedef struct node_t {
    int id;
    const char* name;
    const char* song;
    Set votes;
    Set grades;
    int top_grade;
}*StateNode;

void stateNodeDestroy(StateNode node) {
    if(node == NULL) {
        return;
    }
    if(node->votes) {
        setDestroy(node->votes);
    }
    if(node->grades) {
        setDestroy(node->grades);
    }
    free(node);
}


static StateNode stateNodeCreate(int id,const char* name,const char* song) {
    StateNode state = (StateNode)malloc(sizeof(*state));
    if(state == NULL) {
        return NULL;
    }
    state->id = id;
    state->name = name;
    state->song = song;
    state->top_grade = -1;
    Set votes_set = setCreate(copyVoteElement,
                              freeVoteElement, compareVotes);
    if(votes_set == NULL) {
        free(state);
        return NULL;
    }
    state->votes = votes_set;
    Set grades_set = setCreate(copyGradeElement,
                               freeGradeElement, compareGrades);
    if(grades_set == NULL) {
        stateNodeDestroy(state);
        setDestroy(grades_set);
        return NULL;
    }
    state->grades = grades_set;
    return state;
}

stateResult StateAdd(Set states, int stateId, const char* stateName, const char* songName) {
    if (states == NULL) {
        return STATE_NULL_ARGUMENT;
    }
    if(stateId < 0 ) {
        return STATE_INVALID_ID;
    }
    if(!IsValidName(stateName) || !IsValidName(songName)) {
        return STATE_INVALID_NAME;
    }
    StateNode state_exist = findState(states,stateId);
    if(state_exist != NULL) {
        return STATE_STATE_ALREADY_EXIST;
    }
    free(state_exist);
    StateNode new_state = stateNodeCreate(stateId,stateName,songName);
    if(new_state == NULL) {
        return STATE_OUT_OF_MEMORY;
    }

    if(setAdd(states,new_state) == SET_OUT_OF_MEMORY) {
        stateNodeDestroy(new_state);
        setDestroy(states);
        return STATE_OUT_OF_MEMORY;
    }
    return STATE_SUCCESS;
}

setDestroys уничтожает уже созданный набор, используя setCreate, а setCreate имеет указатели функций в качестве параметров и использует эти функции для копирования / освобождения данных из наборов (ADT)

Ниже приведены функции из другого файла: eurovision.c: eurovisionAddState вызывает stateAdd, который существует в файле state.c -

typedef struct eurovision_t {
    Set states;
    Set judges;
} *Eurovision;

EurovisionResult eurovisionAddState(Eurovision eurovision, int stateId, const char *stateName, const char *songName) {
    stateResult result = StateAdd(eurovision->states, stateId, stateName, songName);
    if (result == STATE_NULL_ARGUMENT) {
        return EUROVISION_NULL_ARGUMENT;
    }
    if (result == STATE_OUT_OF_MEMORY) {
        //setDestroy(eurovision->judges);
        eurovisionDestroy(eurovision);
        return EUROVISION_OUT_OF_MEMORY;
    }
    if (result == STATE_INVALID_ID) {
        return EUROVISION_INVALID_ID;
    }
    if (result == STATE_STATE_ALREADY_EXIST) {
        return EUROVISION_STATE_ALREADY_EXIST;
    }
    if (result == STATE_INVALID_NAME) {
        return EUROVISION_INVALID_NAME;
    }
    return  EUROVISION_SUCCESS;

}

void eurovisionDestroy(Eurovision eurovision) {
    if (eurovision == NULL) {
        return;
    }
    if(eurovision->judges != NULL) {
        setDestroy(eurovision->judges);
    }
    if(eurovision->states != NULL) {
        setDestroy(eurovision->states);
    }
    free(eurovision);
}

eurovisionDestroy очищает Наборы внутри параметра Евровидение и освобождает элемент Евровидения. И последняя часть - это функция, которая существует в test.c: Функция testAddState вызывает функцию eurovisionAddState, которая существует в файле eurovision.c -

bool testAddState() {
  Eurovision eurovision = setupEurovision();
  CHECK(eurovisionAddState(eurovision, 0, "israel", "home"), EUROVISION_SUCCESS);
  //CHECK(eurovisionAddState(eurovision, 1, "malta", "chameleon"), EUROVISION_SUCCESS);
  //CHECK(eurovisionAddState(eurovision, 0, "croatia", "the dream"), EUROVISION_STATE_ALREADY_EXIST);
  //CHECK(eurovisionAddState(eurovision, 0, "israel", "home"), EUROVISION_STATE_ALREADY_EXIST);
  //CHECK(eurovisionAddState(eurovision, -1, "croatia", "the dream"), EUROVISION_INVALID_ID);
  eurovisionDestroy(eurovision);
  return true;
}

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

48 bytes in 1 blocks are definitely lost in loss record 1 of 1
==10451==    at 0x4C29BC3: malloc (vg_replace_malloc.c:299)
==10451==    by 0x402A71: stateNodeCreate (state.c:124)
==10451==    by 0x402DA9: StateAdd (state.c:236)
==10451==    by 0x40082D: eurovisionAddState (eurovision.c:49)
==10451==    by 0x4015E9: testAddState (eurovisionTests.c:169)
==10451==    by 0x4027CE: main (eurovisionTestsMain.c:15)

Это не весь код, я очень уверен, что остальное работает просто отлично, чтобы не вызвать утечек памяти для этого куска кода. Есть идеи?

...