Другие (правильно) указали на серьезные ограничения вашего дизайна, но это исправит то, что у вас есть. Предполагается, что вызывающая сторона знает, какого размера объект выталкивается и выталкивается.
Теоретически, только два из этих изменений абсолютно необходимы, но другие служат для снижения вероятности сбоя (из-за ошибки программиста) с ~ 100% до ~ 80%.
typedef struct sQueueItem {
QueueValue value;
size_t item_size; // <-- you'll need this for the Pop
} QueueItem;
Bool queuePush(Queue * const queue, QueueValue value, size_t val_sz) {
if(isNull(queue) || isFull(queue)) return FALSE;
queue->items[queue->last].value = xmalloc(val_sz);
memcpy(queue->items[queue->last].value, value, val_sz);
queue->items[queue->last].item_size = val_sz; // <-- save the size
queue->last = (queue->last+1) % queue->size;
queue->count += 1;
return TRUE;
}
Bool queuePop(Queue * const queue,
QueueValue **value, // ESSENTIAL: now char **
size_t item_size) // so we can ensure enough room
{
if(isEmpty(queue)) return FALSE;
// just for readability
QueueItem *p = queue->items[queue->first];
// watch for programmer error (maybe you should throw() something)
assert(p->item_size == item_size);
// ESSENTIAL: copy the item to the caller's memory
memcpy(*value, p->value, p->item_size);
free(queue->items[queue->first].value);
queue->first = (queue->first+1) % queue->size;
queue->count -= 1;
return TRUE;
}
Edit:
Было отмечено, что я мог оставить queuePop
как
Bool queuePop(Queue * const queue,
QueueValue *value, // stet
size_t item_size) // so we can ensure enough room
and changed the `memcpy` to
// ESSENTIAL: copy the item to the caller's memory
memcpy(value, p->value, p->item_size);
В какой-то момент я написал это так, что если бы вызывающий передавал NULL в item_size
, queuePop
сделал бы malloc()
и передал бы указатель вызывающему через **value
. Я передумал и думал, что полностью откатился, но ТАК не имеет контроля версий:)