I have the following code in C, trying to develop an Operating System simulation:
Queue.c:
typedef enum {running,readyproc,waiting,suspended}status;
typedef struct pcb {
long pid;
char* pname;
long priority;
long sleepperiod;
long* context;
status stat;
}PCB;
typedef enum {ready, timer, suspend} queuetype;
typedef struct {
int size;
int capacity;
PCB ** data;
queuetype qt;
}Queue;
void queue_init(Queue *q, queuetype qt){
q->size =0;
q->capacity = QUEUE_INITIAL_CAPACITY ;//100
q->data = (PCB **)calloc(q->capacity,sizeof(PCB*));
q->qt = qt;
}
PCB* queue_pop (Queue* q){
PCB* toReturn;
int i;
toReturn = q->data[0];
for (i=0;i<q->size;i++){
q->data[i]=q->data [i+1];
}
free(q->data[q->size]);
q->size--;
printf ("toReturn id:%ld pname: %s\n", toReturn->pid, toReturn->pname);
return toReturn;
}
Knowing that the queue gets initialized and filled with PCBs. I do always get a segafault on calling:
PCB* pcb = queue_pop(&queue);
EDIT:
Here is the function that would fill the queue:
void queue_append(Queue *q, PCB* value)
{
q->data[q->size++] = value;
}
EDIT2:
the printf before the return in queue_pop returns this:
toReturn id: 2 pname: test1c_a
which corresponds to what I want to pop from that queue.
for (i=0;i<q->size;i++){
q->data[i]=q->data [i+1];
}
If q->size == q->capacity, then you'll run off the end of q->data (it will access q->data[q->capacity], which is one past its allocation length).
P.S. There are much more efficient ways to do this.
Below seems to be a problem.
free(q->data[q->size]);
lets say two elements are in Queue q->size = 2 hold by
q->data[0] and q->data[1]
so when queue_pop called. Above code will free q->data[2]. This may leads to seg-fault.
Related
i am studying queue in c and trying to make basic queue program. But couldn't manage to allocate memory for my array. Here is my queue declaration and my createqueue function. After allocating memory space for myQueue, i should allocate for array aswell but i dont know how. Should i just type myQueue->array =(myQueue)malloc(sizeof(myQueue)); will it work ?
struct QueueRecord
{
int capacity;
int front;
int rear;
int size;
int *array;
};
typedef struct QueueRecord *Queue;
Queue CreateQueue(int maxElements)
{
Queue myQueue;
if (maxElements<MIN_QUEUE_SIZE)
{
printf("Queue is too small\n");
return;
}
myQueue = (Queue*)malloc(sizeof(Queue));
if (myQueue == NULL)
printf("out of memmory space");
myQueue->array =(myQueue)malloc(sizeof(myQueue));
myQueue->capacity=maxElements;
MakeEmptyQueue(myQueue);
return myQueue;
}
i should allocate for array aswell but i dont know how
because of the line
myQueue->capacity=maxElements;
the logic is to have
myQueue->array = malloc(sizeof(int) * maxElements);
Should i just type myQueue->array =(myQueue)malloc(sizeof(myQueue)); will it work ?
only in case sizeof(myQueue) is greater than sizeof(int) * maxElements, but you only check maxElements not too small, when maxElements is enough large the behavior is undefined (typically when maxElements is greater than 6 when the size of a pointer is the double of the size of an int).
Out of that :
It is a bad idea to have a typedef defining a pointer, better to have the pointers explicit in the code to see them
the first return; must be return NULL;
knowing myQueue is NULL do not dereference it after, you can directly return NULL after the printf
you check the first malloc does not return NULL, do also for the second, typically in the same if
For instance :
struct QueueRecord
{
int capacity;
int front;
int rear;
int size;
int *array;
};
typedef struct QueueRecord Queue;
void MakeEmptyQueue(Queue *);
Queue * CreateQueue(int maxElements)
{
Queue * myQueue;
if (maxElements < MIN_QUEUE_SIZE)
{
printf("Queue/maxElements is too small\n");
return NULL;
}
if (((myQueue = malloc(sizeof(Queue))) == NULL) ||
((myQueue->array = malloc(sizeof(int) * maxElements)) == NULL))
{
printf("out of memory space\n");
free(myQueue); /* to avoid memory leak, no problem if myQueue is NULL */
return NULL;
}
myQueue->capacity = maxElements;
MakeEmptyQueue(myQueue);
return myQueue;
}
I'm using malloc() function in order to create a queue in C, the problem is that when I use the dequeue() function I leave an unreferenced element. I have to use this function lots of times per second, so I would like to know which is the best way to handle it or if there is a better way than using malloc(). These are the two functions:
void enqueue(struct Queue *q, char c){
//adds an element to the queue
struct Member* m = malloc(sizeof *m);//in order to make m global
if(!m){ perror("malloc");exit(EXIT_FAILURE);}
if(q->length == 0){
m->ch = c;
q->first = m;
q->last = m;
}else{
m->ch = c;
q->last->next = m;
q->last = m;
}
q->length++;
}
char dequeue(struct Queue *q){
//returns the first element of the queue an delete it
char c;
if(q->length >0){
q->length--;
c = q->first->ch;
q->first= q->first->next;
//CLEAR THE UNREFERENCED VARIABLE
}
return c;
}
Thanks!
EDIT:
These are the structs that I'm using:
typedef struct Queue{
int length;
struct Member *first;
struct Member *last;
}Queue;
typedef struct Member{
char ch;
struct Member *next;
}Member;
Store the unreferenced variable to a temporary variable first so that you can free it after changing the first node of the queue.
//returns the first element of the queue and delete it
char dequeue(struct Queue *q){
struct Member* temp = q->first;;
char c;
if(q->length >0){
q->length--;
c = q->first->ch;
q->first= q->first->next;
free(temp);
}
return c;
}
You can check more about free here.
I'm trying to implement a queue in c. I have gotten as far as implementing an enqueue function in my code. However, when I am testing it I don't get the desired output. Can someone please tell me what I am doing wrong?
struct queue{
int array[30];
int *front; //pointer to front of queue
int *rear; //pointer to rear of queue
int count; //counts number of elements in queue
};
//initialising a queue
struct queue * new_Queue()
{
struct queue *q;
q->count=0;
q->front=&q->array[-1];
q->rear=&q->array[-1];
return q;
};
int queueCount(struct queue *q)
{
return q->count;
}
int isFull(struct queue *q)
{
if(q->count==30){
printf("%s","Buffer is full!");
return 1;
}
return 0;
}
int isEmpty(struct queue *q)
{
if(q->count==0){
printf("%s","Queue is empty!");
return 1;
}
return 0;
}
int enqueue(struct queue * q,int i)
{
if(isFull(q)){
return 0;
}
if(isEmpty(q)){
q->front+1;
}
int k=*(q->rear+1);
q->array[k]=i;
printf("enque success!");
return 1;
}
int main(int argc, char**argv)
{
int i=10;
struct queue *newQueue;
enqueue(newQueue,i);
int j= queueCount(newQueue);
printf("%d",j);
}
You need memory for your queue. At the moment, you have an uninitialised pointer that points to a random location in memory. Dereferencing that pointer is undefined behaviour and will very likely give you a seg fault.
You have to decide how you want to store your queue. You can either allocate it on the heap with malloc. This is what your function new_Queue should do:
struct queue *new_Queue()
{
struct queue *q = malloc(sizeof(*q)); // TO DO: Error checking
q->count = 0;
q->front = q->array;
q->rear = q->array;
return q;
}
You client code then looks like this:
struct *q = new_Queue();
enqueue(q, x);
// Do more stuff ...
free(q); // Release resources
The queue structure isn't big. You can also allocate it on the stack. In that casen you need an initialisation function :
void queue_init(struct queue *q)
{
q->count = 0;
q->front = q->array;
q->rear = q->array;
}
and call it like:
struct queue *q;
queue_init(&q);
enqueue(&q, 12);
Note the addres-of operator &. You don't have to (and cannot) free the queue here.
You can't access the array at index -1. You could make the front the next element to dequeue and the rear point to the space where the next element is enqueued. In a circular buffer, that will make the cases of empty and full list indistiguishable, but you can use the count to distinguish between them.
I'm trying to delete all nodes from my queue of structures.
Structure:
struct element{
int id;
int sign;
int year;
int month;
double amount;
struct element *next;
};
struct queue{
struct element *head;
int size;
};
And the function I wrote:
void delete(struct queue *queue) {
if (queue->size == 0){
printf("Structure is empty\n");
}
else {
struct element* this;
struct element* other;
for(this=queue->head;this!=NULL;this=other)
{
other=this->next;
free(this);
}
free(queue);
}
}
It doesn't work, and I'm out of ideas. Any suggestions?
In your delete routine, you do not free the queue if the size is empty, but you do free it if the size is non-empty. You should probably do the same for both cases. That is, either don't free in both places, or free in both places.
It is bothersome to need to figure out what the right thing to do is, because delete can not know how the queue was allocated. Given your current design, a way out may be to pass a flag to delete to indicate what it should do:
void delete(struct queue *queue, int do_free) {
if (queue->size == 0){
printf("Structure is empty\n");
}
else {
struct element* this;
struct element* other;
for(this=queue->head;this!=NULL;this=other) {
other=this->next;
free(this);
}
queue->head = 0;
queue->size = 0;
}
if (do_free) free(queue);
}
struct queue new;
/* ... */
delete(&new, 0); /* don't free the queue */
struct queue *empty_new = malloc(sizeof(struct queue));
empty_new->size = 0;
delete(empty_new, 1); /* free the empty queue */
Here
struct queue new;
//...
delete(&new);
new is allocated on the stack, so don't call free(queue) in delete.
Instead, set queue->head = NULL; queue->size = 0; to indicate that the queue is now empty as mentioned by #kirill.
How about just passing the first element of the queue.
void delete(element *el ) {
if(el) {
delete(el->next );
free(el);
}
}
with
typedef struct _element{
int id;
int sign;
int year;
int month;
double amount;
struct _element *next;
} element;
you might have forgotten to update at the end of the function the pointer to NULL as well as changing the size of the queue to 0.
Essentially I want qPtr[0] to hold sPtr[0]
struct myQueue{
struct sample* node;
int front;
int size;
int numElements;
};
struct sample{
int field1[5];
char field2[10];
}
int main(){
struct myQueue* qPtr = malloc(10 * sizeof(struct myQueue);
struct sample* samplePtr = malloc(10 * sizeof(struct sample); //assume this array has been initialized
enqueue(qPtr, samplePtr[0]); //this does not work
}
//returns 1 if enqueue was successful
int enqueue(struct myQueue* qPtr, struct sample* sPtr){
qPtr->node[(qPtr->front + qPtr->numElements) % qPtr->size] = sPtr; //code pertains to circular array implementation of queues
return 1;
}
I've been at it for about 2 hours now and would appreciate some clarification on what I'm doing wrong conceptually. thank you!
samplePtr[0] gives the object itself, not a pointer to the object. Try sending &samplePtr[0] or samplePtr itself. enque function, second parameter expects a type of struct sample* and not struct sample.
How about:
enqueue(qPtr, &samplePtr[0]);
The second parameter to enqueue() takes a pointer to a struct sample.
Your code has 2 fundamental problems.
you're passing a struct sample object to enqueue() instead of a pointer to a struct sample. this should be caught by the compiler.
you're setting up an array of queue structures instead of having a single queue structure object that manages an array of pointers to the objects that are on the queue. This is a design problem.
Your code should probably look more like:
struct myQueue{
struct sample* node;
int front;
int size;
int numElements;
};
struct sample{
int field1[5];
char field2[10];
}
struct myQueue q = {0};
int enqueue(struct myQueue* qPtr, struct sample* sPtr);
int main(){
// get memory to hold a collection of pointers to struct sample:
q.node = calloc(10, sizeof(struct sample*));
q.size = 10;
// allocate a sample
struct sample* samplePtr = malloc(sizeof(*samplePtr));
// put the sample on the queue
enqueue(qPtr, samplePtr);
}
//returns 1 if enqueue was successful
int enqueue(struct myQueue* qPtr, struct sample* sPtr){
qPtr->node[(qPtr->front + qPtr->numElements) % qPtr->size] = sPtr; //code pertains to circular array implementation of queues
return 1;
}