Queue Dynamic Array - c

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;
}

Related

Why is this code not working? The code should print the elements but it just runs and then exits without dispalying the elements

#include <stdio.h>
#include <stdlib.h>
struct queue
{
int front;
int rear;
int size;
int *arr;
};
void enqueue(struct queue *q, int value)
{
if(q->rear!=q->size-1)
{
printf("Entry\n");
q->rear++;
q->arr[q->rear] = value;
}
}
int main()
{
struct queue *q; /*struct queue *q=(struct queue *)malloc(sizeof(struct queue));*/
q->front = -1;
q->rear = -1;
q->size = 10;
q->arr = (int *)malloc((q->size) * sizeof(int));
enqueue(q,14);
enqueue(q,7);
enqueue(q,5);
enqueue(q,4);
enqueue(q,3);
enqueue(q,2);
for(int i=0;i<q->rear;i++){
printf("%d ",q->arr[i]);
}
return 0;
}
I was expecting the elements of the queue to be printed.
When the line
"struct queue *q;"
is replaced with this "
*struct queue *q=(struct queue *)malloc(sizeof(struct queue));"
it works, what is the reason?
The segmentation-fault occurs because you have not allocated memory for q.
What you have written as:
struct queue *q;
Is a pointer, that is, a variable that stores the memory address of another variable. You have created something that can point to memory but have not provided it any memory to point to.
malloc provides you memory from the heap, which is a typical way of having memory allocated and is why the commented code works.
An alternative would be to use memory on the stack:
struct queue q;
q.front = -1;
q.rear = -1;
q.size = 10;
q.arr = (int *)malloc((q.size) * sizeof(int));
And then using it as:
enqueue(&q,14);
struct queue *q;
q = (struct queue *)malloc(sizeof(struct queue)); /*In order to write data, you first need to allocated to memory for it. and if you do it like q->arr you will allocated to memory for the second step so (think of this list as an array if you do q->arr you will allocated for arr[1] instead of arr[0])*/
q->front = -1;
q->rear = -1;
q->size = 10;
/but this will only allocate the first part in memory (only for arr[0])/
/*so you can write code in void enqueue(struct queue *q, int value) to allocated a new memory in each operation */
/I understand that you are trying to determine the memory in one go by assigning size to 10 , but you can not do like this.because the part you allocate here is just a value you put in arr[0], you can't use it as the size of your list./

Segfault after returning a pointer

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.

Trouble implementing a queue in C

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.

initialization of flexible array of struct pointers in a struct in c

I'm learning hashtable data structures and I want to make a hashtable with a flexible length array of pointers to struct Link (linked list pieces), so that hashtable initialization will set the array to be a length input into the initialization function.
At first I was getting the error "flexible array not at the end of struct". When its at the end (as shown) the program crashes (but it still compiles). This is my code:
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
int numberOfEntries;
int numberOfBuckets;
Link *Table[];
} HashTable;
HashTable *hashtableInit(int size){
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
It works if I set the array to a constant and input the same value into the init function:
#define SIZE 11
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
Link *Table[SIZE];
int numberOfEntries;
int numberOfBuckets;
} HashTable;
HashTable *hashtableInit(int size){ // works if SIZE is passed into function as size parameter
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
The second code block works perfectly. Any insights would be greatly appreciated. Thanks for your time.
Chris
You should allocate memory as
HashTable *newHT = malloc(sizeof *newHT + size * sizeof newHT->Table[0]);
Your
HashTable *newHT = malloc(sizeof(HashTable));
is wrong, because no space is given for the flexible array member. Should probably be
HashTable *newHT = malloc(sizeof(HashTable)+size*sizeof(Link*));

Removing all nodes from a queue of structures

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.

Resources