В двусвязном списке, на котором я основал достаточное количество кода, похоже, есть ошибка, связанная с тем, как я собираюсь удалить узлы из списка, но я не могу заметить Это. Рассмотрим следующий код:Правильное использование указателей функций
typedef struct DL_LIST
{
uint16 tag;
struct DL_LIST *previous;
struct DL_LIST *next;
void *object;
uint32 size;
} DL_LIST;
Функция используется для удаления узлов следующим образом:
void dl_delete(DL_LIST *node, void (*destructor)(void*))
{
assert(destructor != NULL);
if (node != NULL)
{
dl_extract(node);
if (node->object != NULL)
{
destructor(node->object);
}
free(node);
}
}
где:
DL_LIST *dl_extract(DL_LIST *node)
{
if (node != NULL)
{
if (node->previous != NULL)
{
node->previous->next = node->next;
}
if (node->next != NULL)
{
node->next->previous = node->previous;
}
node->previous = NULL;
node->next = NULL;
}
return node;
}
ли кто-нибудь может обнаружить проблему с тем, как я удаление узлов? Причина, по которой я считаю, что существует проблема, заключается в том, что я использовал DL_LIST
в качестве основы для структуры очереди, а функция, используемая для удаления элементов из очереди, развращает ее, , за исключением, когда я прокомментирую звонок dl_delete
.
EDIT 1. В соответствии с просьбой в комментариях, код очереди следующим образом:
typedef struct QU_LIST
{
DL_LIST *list;
uint32 count;
} QU_LIST;
uint8 qu_remove(QU_LIST *queue, void *object, void (*destructor)(void*))
{
uint8 result = QU_SUCCESS;
uint32 size;
DL_LIST *first_node;
DL_LIST *next_node;
void *marker;
assert(queue != NULL && destructor != NULL);
if (queue->count > 0)
{
first_node = dl_get_first(queue->list);
next_node = dl_get_next(first_node);
marker = dl_get_object(first_node, NULL, &size);
if (marker != NULL)
{
if (object != NULL)
{
memcpy(object, marker, size);
}
}
else
{
result = QU_NO_MEMORY;
}
queue->list = next_node;
dl_delete(first_node, destructor); // this is the problem
--queue->count;
}
else
{
result = QU_EMPTY;
}
return result;
}
где:
DL_LIST *dl_get_first(DL_LIST *list)
{
if (list != NULL)
{
while (list->previous != NULL)
{
list = list->previous;
}
}
return list;
}
DL_LIST *dl_get_next(DL_LIST *node)
{
if (node != NULL)
{
node = node->next;
}
return node;
}
void *dl_get_object(DL_LIST *node, uint16 *tag, uint32 *size)
{
void *marker = NULL;
if (node != NULL)
{
if (tag != NULL)
{
*tag = node->tag;
}
if (size != NULL)
{
*size = node->size;
}
marker = node->object;
}
return marker;
}
EDIT 2. Благодаря стерлингов ответ со стороны Wumpus Q. Wumbley , источник проблемы был сужен до следующего кода, который является частью библиотеки кнопок навигации для встроенной системы.
void bu_test(void)
{
QU_LIST button_list = {0};
BU_OBJECT *object = NULL;
object = bu_create("O");
// object->identifier is "O" at this point.
bu_add(&button_list, "N");
bu_add(&button_list, "S");
bu_add(&button_list, "E");
bu_add(&button_list, "W");
qu_remove(&button_list, object, (void(*)(void*)) &_destructor);
// object->identifier should be "N" at this point, but is not.
}
где:
typedef struct BU_OBJECT
{
char *identifier;
} BU_OBJECT;
uint8 bu_add(QU_LIST *queue, char *identifier)
{
uint8 result = BU_SUCCESS;
BU_OBJECT* object;
assert(queue != NULL && identifier != NULL);
object = bu_create(identifier);
if (object != NULL)
{
result = qu_add(queue, _TAG, object, sizeof(*object));
if (result == QU_NO_MEMORY)
{
_destructor(object);
result = BU_NO_MEMORY;
}
}
else
{
result = BU_NO_MEMORY;
}
return result;
}
и:
BU_OBJECT *bu_create(char *identifier)
{
BU_OBJECT *object = NULL;
char *p;
assert(identifier != NULL);
object = malloc(sizeof(*object));
if (object != NULL)
{
p = malloc(sizeof(*identifier));
if (p != NULL)
{
strcpy(p, identifier);
object->identifier = p;
}
else
{
free(object);
object = NULL;
}
}
return object;
}
и, наконец:
void _destructor(BU_OBJECT *object)
{
free(object->identifier);
free(object);
}
Объекты добавляются к button_list
без ошибок, но кажется, что _destructor
уничтожает параметр объекта, который передается функции qu_remove
, что кажется мне чрезвычайно странным, так как это должен быть объект уничтоженного first_node
, а не параметра.
Я читал, что не заметил никаких ошибок. Опубликовать еще –
Код выглядит хорошо для меня тоже. Предполагая, что все указатели (следующий, предыдущий и объект) являются действительными или NULL, должны быть в порядке. – Zenilogix
Самая деликатная часть кажется memcpy. Вы уверены, что второй аргумент 'qu_remove' указывает на достаточно большую область памяти? –