I would prefer to allocate the nodes outside the push/pop functions. And to do a more "generic" queue, like this:
Code:
#include <stdio.h>
#include <stdlib.h>
// Generic node structure.
// Use "polimorphism" to create your own nodes, like:
//
// struct mynode {
// NODE node_; // MUST be the first member!
//
// int n; // MY node data.
// };
//
typedef struct node
{
struct node *next, *prev;
} NODE;
typedef struct queue
{
struct node *head, *tail;
} QUEUE;
// Returns NULL in case of error.
QUEUE *create_queue ( void )
{
return calloc ( 1, sizeof ( QUEUE ) );
}
void queue_push ( QUEUE *q, void *n )
{
NODE *nptr = n;
if ( q->tail )
{
q->tail->next = nptr;
nptr->prev = q->tail;
}
else
{
q->head = nptr;
nptr->prev = NULL;
}
q->tail = nptr;
nptr->next = NULL;
}
void *queue_pop ( QUEUE *q )
{
NODE *n, *p;
n = NULL;
if ( q->tail )
{
n = q->tail;
p = q->tail->prev;
q->tail = p;
}
if ( ! q->tail )
q->head = NULL;
else
q->tail->next = NULL;
return n;
}
void destroy_queue ( QUEUE *q, void ( *dtor ) ( void * ) )
{
NODE *n;
while ( q->head )
{
n = q->head->next;
if ( dtor )
dtor ( q->head );
q->head = n;
}
free ( q );
}
// ----------------------------
// Usage example:
// ----------------------------
// My own node: Notice the first member.
struct mynode
{
NODE node_;
int n;
};
// helper function to allocate new nodes.
static struct mynode *create_node ( int n )
{
struct mynode *p;
if ( ! ( p = malloc ( sizeof * p ) ) )
{
fprintf ( stderr, "ERROR allocating node (n=%d).\n", n );
// Didn't bother with housekeeping...
exit ( EXIT_FAILURE );
}
p->n = n;
return p;
}
int main ( void )
{
QUEUE *q;
struct mynode *p;
if ( ! ( q = create_queue() ) )
{
fputs ( "ERROR creating queue.\n", stderr );
return EXIT_FAILURE;
}
p = create_node ( 1 );
queue_push ( q, p );
p = create_node ( 2 );
queue_push ( q, p );
p = create_node ( 3 );
queue_push ( q, p );
// While there is nodes to "pop", show their data
// and free them.
while ( p = queue_pop ( q ) )
{
printf ( "POP: %d\n", p->n );
free ( p );
}
// Destroy the list and all remaining nodes, if any.
// there will be none, after the loop above.
// Notice my "destructor" is the free() function.
destroy_queue ( q, free );
return EXIT_SUCCESS;
}