clinked-listqueuememory-access

Linked List Queue in C: Exception thrown: read access violation. temp was 0x740069


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

Current output of my Queue


Solution

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