Очередь связанного списка в C: выброшено исключение: нарушение прав доступа для чтения. темп был 0x740069 - PullRequest
1 голос
/ 30 мая 2020

Я делал простую программу очереди связанных списков, используя C, и я получил это исключение из моей функции печати. ​​

Выброшено исключение: нарушение прав доступа на чтение. temp был 0x740069.

Я все еще новичок, когда дело доходит до языка C, поэтому я еще не привык к управлению памятью и использованию указателей. Поэтому я не уверен, связана ли причина с моей функцией pu sh или моей функцией печати. ​​

Поэтому я хотел бы спросить, в чем причина этого исключения и как ее исправить.

Мой код выглядит следующим образом:

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

И результат показан на изображении ниже

Текущий вывод моей очереди

Ответы [ 2 ]

1 голос
/ 31 мая 2020

Ну, в моем случае я использую поле для хранения размера списка, но это можно сделать и без него, вот моя реализация для очереди, я добавил несколько комментариев для ясности, может быть, вы найдете это полезным. и я добавил всего несколько функций, вы можете добавить больше, если хотите, это просто для запуска:)

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

вывод

Is empty: true
Size: 1
Is empty: false
{txt1, txt2, txt3}
Size: 2
Size: 3
{txt2, txt4, txt5}
Size: 0
{}
Size: 1
{txt}

Хорошо, согласно вашему комментарию:

Я сейчас экспериментирую с вашей версией прямо сейчас, я хочу спросить, не хочу ли я использовать Queue * a = Queue_create (); в основной функции, но вместо этого я хочу сделать Queue * a = NULL; а затем выделите для него место в функции pu sh. Как бы вы это сделали?

Вы можете сделать это таким образом, обратите внимание, что вы все равно можете использовать другие функции таким же образом без каких-либо изменений. и даже вы все еще можете использовать Queue_create Directly как Queue *q = Queue_create(); как в первой части.

#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}
1 голос
/ 30 мая 2020

В вашем коде есть несколько ошибок. Многие были бы пойманы, если бы у вас были включены предупреждения о включении вашего компилятора.

В push: вы хотите получить указатель на свою очередь. Но в основном вы передаете двойной указатель . В основном вы также объявляете свою очередь как пустой указатель Queue *q = NULL;, поэтому очереди нет (даже не пустой очереди). Вы можете сделать две вещи:

  • получить двойной указатель в push и выделить пустую очередь, которую вы возвращаете в указателе;

  • объявить очередь в main не как указатель, а как пустую очередь, Queue q = {0}; и теперь вызвать push(&q, "a");

В push вы также делаете ошибку при распределении данных .
С temp->data = (char*)malloc(sizeof(char)); вы выделяете только ОДИН символ.
Затем с temp->data = word; вы выбрасываете его. Вам следует сделать:

temp->data = malloc(strlen(word)+1);
strcpy(temp->data, word);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...