I was making simple Linked list Queue program using C and i get this exception from my print function.
Exception thrown: read access violation. temp was 0x740069.
I'm still a beginner when it comes to C language so I don't getting use to managing memory and using pointers yet. So I'm not sure if the cause comes from my push function or my print function.
So i would like to ask what is the cause of this exception and how to fix it.
My code are as follow
struct node_struct {
char *data;
struct node_struct *next;
};
typedef struct node_struct Node;
struct queue_struct {
Node *head, *tail;
};
typedef struct queue_struct Queue;
void push(Queue *q, char *word)
{
// IMPLEMENT
Node* temp = (Node*)malloc(sizeof(Node));
temp->data = (char*)malloc(sizeof(char));
temp->data = word;
temp->next = NULL;
if (q->head == NULL )
{
q->head= temp;
}
else
{
q->tail->next = temp;
}
q->tail = temp;
q->tail->next = q->head;
}
char *pop(Queue *q)
{
// IMPLEMENT
Node* temp = q->head;
char n = q->head->data;
q->head = q->head->next;
free(temp);
return(n);
}
void print(Queue *q)
{
// IMPLEMENT
if (q == NULL)
{
printf("No Items\n");
}
else
{
//Node* temp = (Node*)malloc(sizeof(Node));
Node* temp = q->head;
while (temp != NULL)
{
printf("%c\n", temp->data);
temp = temp->next;
}
}
}
void print(Queue *q)
{
// IMPLEMENT
if (q == NULL || isEmpty(q))
{
printf("No Items\n");
}
else
{
//Node* temp = (Node*)malloc(sizeof(Node));
Node* temp = q->head;
while (temp != NULL)
{
printf("%c\n", temp->data);
temp = temp->next;
}
}
}
int isEmpty(Queue *q)
{
// IMPLEMENT
if (q->head == NULL)
return 1;
return 0;
}
void delete(Queue *q)
{
// IMPLEMENT
Node* temp;
while (q->head != NULL)
{
temp = q->head;
q->head = q->head->next;
delete(temp);
}
q->tail = NULL;
}
int main(int argc, char **argv)
{
Queue *q = NULL;
// print the queue
print(q);
// push items
push(&q, "a");
push(&q, "b");
push(&q, "c");
print(q);
}
And the output is in image below
Well in my case I use a field to store the size of the list, but it can be done without it, here is my implementation for a queue, I have added some comments for clarity, maybe you will find it useful. and i have added just few functions, you can add more if you like, it's just for giving you a startup :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// make an alias for better readability
typedef char * String;
typedef struct node_struct {
String data;
struct node_struct *next;
} Node;
typedef struct queue_struct {
Node *head, *tail;
} Queue;
// create a new node, allocating the memory and copying the value...
Node * Node_create(String str) {
Node *node = (Node *)malloc(sizeof(Node));
if(node == NULL) return NULL;
node->data = (String)malloc(strlen(str) + 1);
if(node->data == NULL) return NULL;
strcpy(node->data, str);
node->next = NULL;
return node;
}
// delete the node
void Node_delete(Node *node) {
free(node->data);
free(node);
}
// create a new Queue and set the head and tail to NULL(empty)
Queue * Queue_create() {
Queue *queue = (Queue *)malloc(sizeof(Queue));
if(queue == NULL) return NULL;
queue->head = queue->tail = NULL;
return queue;
}
// add a new node to the queue
bool Queue_push(Queue *q, String str) {
Node* node = Node_create(str);
if(node == NULL) return false;
// empty queue
if(q->head == NULL) {
q->head = q->tail = node;
// has only one element
}else if(q->head == q->tail) {
q->head->next = q->tail = node;
// has more than one element
}else {
q->tail->next = node;
q->tail = q->tail->next;
}
return true;
}
// print the elements of the queue
void Queue_print(Queue *q) {
Node *tmpNode = q->head;
printf("{");
// loop over the queue
while(tmpNode != NULL) {
printf("%s", tmpNode->data);
// don't print ',' if its the last element
tmpNode != q->tail && printf(", ");
tmpNode = tmpNode->next;
}
printf("}");
}
// get the size of the queue
int Queue_size(Queue *q) {
Node *tmpNode = q->head;
int size = 0;
while(tmpNode != NULL) {
tmpNode = tmpNode->next;
size++;
}
return size;
}
// remove the last element in the queue
String Queue_pop(Queue *q) {
String s = NULL;
// empty queue
if(q->head == NULL) return s;
// has one element
if(q->head == q->tail) {
s = q->head->data;
Node_delete(q->head);
q->head = q->tail = NULL;
// has two elements
}else if(q->head->next == q->tail) {
s = q->tail->data;
Node_delete(q->tail);
q->tail = q->head;
q->head->next = q->tail;
q->tail->next = NULL;
// has more than two
}else {
s = q->tail->data;
Node *tmpNode = q->head, *lastNode;
// loop over the queue and get the element before the last one
while(tmpNode != NULL) {
lastNode = tmpNode;
tmpNode = tmpNode->next;
// delete the last element and replace it with the previous element
if(tmpNode == q->tail) {
Node_delete(q->tail);
q->tail = lastNode;
q->tail->next = NULL;
return s;
}
}
}
return s;
}
// remove the first element in the queue
String Queue_shift(Queue *q) {
String s = NULL;
// empty queue
if(q->head == NULL) return NULL;
// has one element
if(q->head == q->tail) {
s = q->head->data;
Node_delete(q->head);
q->head = q->tail = NULL;
// has more than one
} else {
// just delete the first element and replace it with the next one
Node *tmpNode = q->head->next;
s = q->head->data;
Node_delete(q->head);
q->head = tmpNode;
}
return s;
}
// remove all the elements in the queue
void Queue_clear(Queue *q) {
Node *tmpNode = q->head;
for(int i = 0, n = Queue_size(q);i < n; i++) {
tmpNode = tmpNode->next;
// using the Queue_shift instead of Queue_pop because it's faster(low processing cost)
Queue_shift(q);
}
}
// remove all the elements in the queue and free the memory of the queue
void Queue_delete(Queue *q) {
Queue_clear(q);
free(q);
}
// check if the queue is empty
bool Queue_isEmpty(Queue *q) {
return q->head == NULL;
}
int main(void) {
Queue *a = Queue_create();
printf("Is empty: %s\n", Queue_isEmpty(a) ? "true" : "false");
Queue_push(a, "txt1");
printf("Size: %d\n", Queue_size(a));
printf("Is empty: %s\n", Queue_isEmpty(a) ? "true" : "false");
Queue_push(a, "txt2");
Queue_push(a, "txt3");
Queue_print(a);
Queue_shift(a);
printf("\nSize: %d\n", Queue_size(a));
Queue_pop(a);
Queue_push(a, "txt4");
Queue_push(a, "txt5");
printf("Size: %d\n", Queue_size(a));
Queue_print(a);
Queue_clear(a);
printf("\nSize: %d\n", Queue_size(a));
Queue_print(a);
Queue_push(a, "txt");
printf("\nSize: %d\n", Queue_size(a));
Queue_print(a);
Queue_delete(a);
return 0;
}
output
Is empty: true
Size: 1
Is empty: false
{txt1, txt2, txt3}
Size: 2
Size: 3
{txt2, txt4, txt5}
Size: 0
{}
Size: 1
{txt}
Ok according to your comment:
I currently experiment with your version right now i want to ask if i don't want to use Queue *a = Queue_create(); in the main function but instead i want to made Queue *a = NULL; and then allocate space for it in push function how would you do it?
You can do it this way, note that you can still use the other functions the same way with no modifications. and even you still can use Queue_create Directly like Queue *q = Queue_create();
like in the first part.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// make an alias for better readability
typedef char * String;
typedef struct node_struct {
String data;
struct node_struct *next;
} Node;
typedef struct queue_struct {
Node *head, *tail;
} Queue;
// create a new node, allocating the memory and copying the value...
Node * Node_create(String str) {
Node *node = (Node *)malloc(sizeof(Node));
if(node == NULL) return NULL;
node->data = (String)malloc(strlen(str) + 1);
if(node->data == NULL) return NULL;
strcpy(node->data, str);
node->next = NULL;
return node;
}
// delete the node
void Node_delete(Node *node) {
free(node->data);
free(node);
}
// create a new Queue and set the head and tail to NULL(empty)
Queue * Queue_create() {
Queue *queue = (Queue *)malloc(sizeof(Queue));
if(queue == NULL) return NULL;
queue->head = queue->tail = NULL;
return queue;
}
// add a new node to the queue
bool Queue_push(Queue **q, String str) {
// if there is no allocated Queue then we need to allocate one using the Queue_create() we already have
if(*q == NULL) {
*q = Queue_create();
if(*q == NULL) return false;
}
Node* node = Node_create(str);
if(node == NULL) return false;
// empty queue
if((*q)->head == NULL) {
(*q)->head = (*q)->tail = node;
// has only one element
}else if((*q)->head == (*q)->tail) {
(*q)->head->next = (*q)->tail = node;
// has more than one element
}else {
(*q)->tail->next = node;
(*q)->tail = (*q)->tail->next;
}
return true;
}
// print the elements of the queue
void Queue_print(Queue *q) {
if(q != NULL) {
Node *tmpNode = q->head;
printf("{");
// loop over the queue
while(tmpNode != NULL) {
printf("%s", tmpNode->data);
// don't print ',' if its the last element
tmpNode != q->tail && printf(", ");
tmpNode = tmpNode->next;
}
printf("}");
}
}
// get the size of the queue
int Queue_size(Queue *q) {
if(q == NULL) return 0;
Node *tmpNode = q->head;
int size = 0;
while(tmpNode != NULL) {
tmpNode = tmpNode->next;
size++;
}
return size;
}
// remove the last element in the queue
String Queue_pop(Queue *q) {
if(q == NULL) return NULL;
String s = NULL;
// empty queue
if(q->head == NULL) return s;
// has one element
if(q->head == q->tail) {
s = q->head->data;
Node_delete(q->head);
q->head = q->tail = NULL;
// has two elements
}else if(q->head->next == q->tail) {
s = q->tail->data;
Node_delete(q->tail);
q->tail = q->head;
q->head->next = q->tail;
q->tail->next = NULL;
// has more than two
}else {
s = q->tail->data;
Node *tmpNode = q->head, *lastNode;
// loop over the queue and get the element before the last one
while(tmpNode != NULL) {
lastNode = tmpNode;
tmpNode = tmpNode->next;
// delete the last element and replace it with the previous element
if(tmpNode == q->tail) {
Node_delete(q->tail);
q->tail = lastNode;
q->tail->next = NULL;
return s;
}
}
}
return s;
}
// remove the first element in the queue
String Queue_shift(Queue *q) {
if(q == NULL) return NULL;
String s = NULL;
// empty queue
if(q->head == NULL) return NULL;
// has one element
if(q->head == q->tail) {
s = q->head->data;
Node_delete(q->head);
q->head = q->tail = NULL;
// has more than one
} else {
// just delete the first element and replace it with the next one
Node *tmpNode = q->head->next;
s = q->head->data;
Node_delete(q->head);
q->head = tmpNode;
}
return s;
}
// remove all the elements in the queue
void Queue_clear(Queue *q) {
if(q != NULL) {
Node *tmpNode = q->head;
for(int i = 0, n = Queue_size(q);i < n; i++) {
tmpNode = tmpNode->next;
// using the Queue_shift instead of Queue_pop because it's faster(low processing cost)
Queue_shift(q);
}
}
}
// remove all the elements in the queue and free the memory of the queue
void Queue_delete(Queue *q) {
if(q != NULL) {
Queue_clear(q);
free(q);
}
}
// check if the queue is empty
bool Queue_isEmpty(Queue *q) {
return q == NULL || q->head == NULL;
}
int main(void) {
Queue *a = NULL;
Queue_print(a);
printf("Is empty: %s\n", Queue_isEmpty(a) ? "true" : "false");
Queue_push(&a, "txt1");
printf("Size: %d\n", Queue_size(a));
printf("Is empty: %s\n", Queue_isEmpty(a) ? "true" : "false");
Queue_push(&a, "txt2");
Queue_push(&a, "txt3");
Queue_print(a);
Queue_shift(a);
printf("\nSize: %d\n", Queue_size(a));
Queue_pop(a);
Queue_push(&a, "txt4");
Queue_push(&a, "txt5");
printf("Size: %d\n", Queue_size(a));
Queue_print(a);
Queue_clear(a);
printf("\nSize: %d\n", Queue_size(a));
Queue_print(a);
Queue_push(&a, "txt");
printf("\nSize: %d\n", Queue_size(a));
Queue_print(a);
Queue_delete(a);
return 0;
}
output
Is empty: true
Size: 1
Is empty: false
{txt1, txt2, txt3}
Size: 2
Size: 3
{txt2, txt4, txt5}
Size: 0
{}
Size: 1
{txt}