C: Освобождение массива malloc’d в неподходящее время?

#c #arrays #free

#c #массивы #Бесплатно

Вопрос:

У меня есть struct cell ->

 struct cell {
    double x, y, h, g, rhs;
    struct key *keys;
};
  

И я использую следующий метод для освобождения ячейки ->

 void cellFree(struct cell *c)   {
    // Free the keys
    free(c->keys);

    // Free the cell itself.
    free(c);
}

void cellFreeSors(struct cell *cn)  {
    int i;
    for(i = 0; i < 5; i  )  {
        // Free keys
        free(cn[i].keys);
    }
    // Free array
    free(cn);
}
  

Теперь я столкнулся со странной проблемой с одним из созданных мной массивов malloc’d.
В принципе, я пытаюсь найти соседей ячейки и выполняю некоторую обработку на основе их значений, используя следующие два метода ->

 struct cell * cellGetSuccessors(struct cell *c, struct cell *sstart, struct cell *sgoal, double km) {
        int i;

        // CREATE 5 CELLS
        struct cell *cn = malloc(5 * sizeof (struct cell));
            if (cn == NULL) {
            printf("--> Unable to malloc *cn!n");
            errno = ENOMEM;
            return NULL;
            }

        for(i = 0; i < 5; i  )  {
            cn[i].keys = malloc(sizeof(struct key));
                if (cn[i].keys == NULL) {
                printf("--> Unable to malloc *cn[%d].keys!n", i);
                errno = ENOMEM;
                return NULL;
            }
            cellCopyValues(amp;cn[i], c);
        }

        // MAKE THEM NEIGHBORS
        // PROCESS

        return cn;
    }


    double cellRHS(struct cell *c, struct cell *sstart, struct cell *sgoal, double km, struct cell * prevCell)  {
        // GET NEIGHBORS of c
        struct cell *cn = cellGetSuccessors(c, sstart, sgoal, km);
        double minsum;

        // SOME PROCESS TO UPDATE minsum
        minsum = 5.232111; // SAY

        // Free memory
        cellFreeSors(cn);

        return minsum;
    }
  

Проблема в том, что когда я вызываю cellFreeSors() in cellRHS() , я сталкиваюсь с проблемами позже..
Вот как вызываются эти функции..

 struct cell *u = cellCreateNew();
u->rhs = cellRHS(u, sstart, sgoal, km, prevCell);
queueAdd(amp;U, u);
  

Это приводит к ошибке сегментации при попытке распечатать мою очередь ->

     QUEUE CONTENTS
    ==================================================================
    F -> 0x2354550
    L - >0x2354550
    (1) [0x2354550] X 50.000000, Y 45.000000    PREV: (nil) NEXT: 0x4014000000000000
Segmentation fault
  

Как вы можете видеть, СЛЕДУЮЩАЯ запись, похоже, по какой-то причине инициализирована.
Тот же код при выполнении БЕЗ cellRHS() работает нормально .. ->

 struct cell *u = cellCreateNew();
queueAdd(amp;U, u);

    QUEUE CONTENTS
    ==================================================================
    F -> 0x2354550
    L - >0x2354550
    (1) [0x2354550] X 50.000000, Y 45.000000    PREV: (nil) NEXT: (nil)
  

Почему cellFreeSors() возникает эта проблема? Мне не нужны созданные соседи u за пределами cellRHS . Что я делаю не так?

Спасибо..

** РЕДАКТИРУЕТ структуру для queue_node следующим образом

 /* QUEUE NODE
 * ----------------------------
 * Contains a struct cell c and
 * reference to next queue_node
 */
struct queue_node   {
    struct cell *c;
    struct queue_node *next;
    struct queue_node *prev;
};

/* PRIORITY QUEUE
 * ----------------------------
 * The queue itself, with first
 * and last pointers to queue_nodes
 */
struct priority_queue   {
    struct queue_node *first;
    struct queue_node *last;
};
  

queuePrint() Метод показывает содержимое очереди ->

 void queuePrint(struct priority_queue *q)
{
    printf("nntQUEUE CONTENTSnt==================================================================n");
    int i = 1;
    struct queue_node *temp = q->first;
    printf("tF -> %pntL -> %pn", q->first, q->last);
    while(temp != NULL) {
        printf("t(%d) [%p]tX %f, Y %ftPREV: %ptNEXT: %p", i, temp, temp->c->x, temp->c->y, temp->prev, temp->next);
        printf("n");
        temp = temp->next;
        i  ;
    }
    printf("nn");
}
  

Комментарии:

1. Нет необходимости настраивать ENOMEM самостоятельно; malloc сделает это за вас. На самом деле, это может скрывать другие ошибки. Что cellCopyValues делает?

2. Я не вижу указателя prev или next в вашей структуре. И вы не включили код, который нарушает сегментацию (я предполагаю, что это в queueAdd или что-то еще, отображающее содержимое очереди).

3. не забывайте о вопросе Ларсмана на cellCopyValues , плюс он точен в том, что касается errno , вам не следует его менять.

4. Вы инициализируете указатели prev и next при создании записи очереди? Код для queueAdd() может помочь. Но, когда вы создаете новый элемент очереди, инициализируйте его перед добавлением в очередь.

Ответ №1:

Несколько предложений здесь:

  1. Используйте централизованный метод allocCell() и FreeCell(). Это позволяет точно отслеживать каждую выделенную и освобожденную ячейку.

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

  3. Напишите процедуры трассировки для ячейки, чтобы убедиться, что ваши процедуры освобождают только выделенные ячейки, что любая ячейка освобождается только один раз и т.д. Вы могли бы даже написать хэш-таблицу для хранения идентификаторов выделенных и освобожденных ячеек (конечно, только во время отладки) и написания проверочных проверок.

  4. Вероятно, вы снова столкнетесь с ошибками памяти, если не сделаете этого.

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

  6. Переключитесь на C # или java и ничего не освобождайте 🙂