user1611830
user1611830

Reputation: 4857

Using pointers for queue type

I am very new to c and pointers. Each time I thin k I have understood it, there comes a problem that I don't really understand (I spent some time reading c docs but pointers still remain unclear to me) :

typedef struct {
        int q[QUEUESIZE+1];
        int first;
        int last;
        int count;
} queue;

enqueue(queue *q, int x)
{
  if (q->count >= QUEUESIZE)
        printf("Warning: queue overflow enqueue x=%d\n",x);

  else {
    q->last = (q->last+1) % QUEUESIZE;
    q->q[ q->last ] = x;
    q->count = q->count + 1;
  } 
}

I hope my question will not be too opaque but could someone explain the use of pointer in enqueue function? I thought the principle of queuing was to allocate some precise successive memory addresses, but it is not that for sure....

Upvotes: 0

Views: 2336

Answers (2)

wildplasser
wildplasser

Reputation: 44240

struct queue {
        unsigned first;
        unsigned count;
        int q[QUEUESIZE];
        };

int enqueue(struct queue *q, int x)
{
  if (q->count >= QUEUESIZE) {
        fprintf(stderr, "Warning: queue overflow enqueue x=%d\n", x);
        return -1;
        }

  q->q[ (q->first+q->count++) % QUEUESIZE ] = x;
  return 0; /* success */ 
}

A few points:

  • diagnostic output should go to stderr
  • Using unsigned types for counts and offsets will (in most cases) avoid numerical underflow (or will transform it into overflow, which will fail faster ;-)
  • you don't need three elements {head, tail, count}, only two {head, count} will suffice
  • fewer variables := fewer assignments := fewer lines = less chance for error.
  • The QUEUESIZE in the range check and modulo division should probably be replaced by sizeof q->q / sizeof q->q[0], which is more robust.

Upvotes: 1

Déjà vu
Déjà vu

Reputation: 28830

enqueue takes a queue queue (queue of type queue) and add an element in it (which is made of an integer.

queue *q is a pointer, since, probably

  • there could be more than one queue, and the parameter tells what queue we're talking about
  • in order to avoid a global variable, the queue is given as parameter - we want a reference to the queue so that it can be modified, and the modification will stay live even after exiting enqueue

Passing a queue by value, as

enqueue(queue q, int x) { ...

would mean

  • a lot of data given as parameter (copy of the queue myqueue to the q parameter)
  • when q is modified, the modification is made on q within the enqueue function. The initially provided queue (myqueue) as parameter would not be modified

For instance

enqueue(queue q, int x) { 
  q.count++; // only the local q.count is changed, not myqueue.count
  // ...
}

// ...

queue myqueue;
// ...
enqueue (myqueue, 3); // enqueue changes its local parameter, myqueue is not affected

Besides, the enqueue function implementation could be optimized... (see wildplasser answer below who suggests a better queue implementation)

Upvotes: 3

Related Questions