Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Освобождение указателя на структуру указателей

Автор вопроса: randy newfieldОтветов: 2

У меня возникла ситуация, которую я никак не могу решить. Это вызывает медленную, но со временем катастрофическую утечку памяти. Я заметил, что, хотя я освобождаю структуру указателей (которую я передал функции), я забыл освободить указатели внутри них, что, согласно valgrind, приводит к утечкам памяти. Я попытался освободить память указателей из функции, но не могу устранить сообщение об ошибке error: request for member 'xxx' in something not a structure or union.

Это краткий обзор моей программы. Я создаю структуру данных, которая содержит переменные, необходимые для многопотоковой функции. Есть основная функция, которой передаются аргументы, и в зависимости от данных она заполняет соответствующую структуру. Затем он запускает поток фактической функции (передавая структуру как указатель void), в котором я беру и воссоздаю фактическую структуру внутри функции. Это код:

void cmd_test(char *sender, char **args, int arg_count) {
    char command[1024];

    // creates my exec pointer structure
    exec_struct *exec = malloc(sizeof(exec_struct));

    // adds a thread identifier to a struct to keep track of threads
    exec->tID = thread_add(EXEC);

    // the first malloc which I don't know how to free
    exec->sender = malloc(sizeof(char) * strlen(sender) + 1);
    sprintf(exec->sender, "%s", sender);

    // move ahead 5 arguments (there will always be 5 or more arguments supplied
    // by the calling function)
    args += 5;
    memset(command, 0, sizeof(command));

    // concatenate the remaining arguments into a cstring
    while(*args[0]) {
        printf("arg: %s\n", *args);
        sprintf(command, "%s %s", command, *args);
        args++;
    }

    // the second malloc which I don't know how to free
    exec->exec = malloc(sizeof(char) * strlen(command) + 1);

    // copy the string to the structure from pointer+1 to end of pointer
    // removes a space created from the first iteration of previous loop)
    sprintf(exec->exec, "%s", command + 1);

    printf("command:%s\n exec:%s\n", command, exec->exec);

    //stores an actual thread id into a struct of threads to keep track of
    //the actual thread (other one is just to keep track of what type
    //of thread is running)
    threads[exec->tID].tID = Thread_Start(exec_cmd, exec);
}

Вот как я настроил свою структуру с некоторыми комментариями о том, что происходит. Thread_Start() - это просто функция, которая принимает адрес функции и адрес структуры для передачи функции с нитями. Это функция exec_cmd:

void *exec_cmd(void *param) {
    char buf[1024];
    FILE *command;

    // recreate the structure locally inside the thread
    exec_struct exec = *((exec_struct *)param);

    // causes the error described
    // free(param.exec);
    // free(param.sender);

    // free the structure memory from the thread creating function.
    free(param);

    memset(buf,0,1024);
    sprintf(buf,"%s",exec.exec);
    command = popen(buf,"r");

    while(!feof(command)) {
        memset(buf,0,1024);
        fgets(buf,1024,command);
        printf("%s\n", buff);
        sleep(1);
    }

    pclose(command);

    // cleans itself up from the tracking structures
    thread_remove(EXEC, 0);

    // exits cleanly
    return NULL;
}

Чтобы устранить ошибку, я попытался создать структуру перед ней, но ошибка все еще сохраняется. Использование оператора -> приводит к ошибке void* deference.

Я также удалил некоторые из функций, таких как проверка того, запущен ли уже поток, и проверка ошибок для уменьшения беспорядка. Обе функции работают в моем приложении (он создает поток, сохраняет его в порядке, отлично передает и создает новую структуру и выполняет переданную команду). Просто я не могу понять, как освободить два вызова malloc, которые я сделал внутри потока. Как я могу решить эту проблему?

  • while(!feof(command)) {} всегда неправильно. wildplasser 25.12.2012

cmultithreadingmemory-managementmalloc

Ответы

Ответ 1 · рейтинг 2 · JasonD

exec_struct exec = *((exec_struct *)param);

//free(param.exec);
//free(param.sender);

param - это переданный void *. Ваша копия структуры называется exec.

Возможно, вы имели в виду:

free(exec.exec);
free(exec.sender);

Однако имейте в виду, что вы сразу же получите доступ к exec.exec позже в той же функции. Вы не можете этого сделать, если уже освободили его. Копирование структуры не означает, что вы скопировали память, на которую указывают указатели.

Эта строка:

sprintf(buf,"%s",exec.exec);

Это должно произойти до того, как exec.exec будет освобожден.

Ответ 2 · Mats Petersson

Общий принцип заключается в том, что вы начинаете с "самого глубокого" уровня структуры и продвигаетесь вверх. Никогда не позволяйте освобождать что-либо на "верхнем" уровне, пока не будет освобождено все, что находится внутри него. Другими словами, используйте порядок, противоположный тому, который вы назвали malloc.

Не вижу смысла делать:

exec_struct exec = *((exec_struct *)param);

Я бы просто скопировал исходный указатель:

exec_struct *exec = (exec_struct *)param;

Затем

free(exec->sender);
free(exec->command);

free(exec);

Конечно, вы не должны делать НИЧЕГО освобождения, пока не закончите использовать структуру exec.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы