简体   繁体   English

队列结构在被调用一次后丢失元素值

[英]Queue struct losing element values after being called once

I am writing a queue struct in C that takes strings (char pointers) as the element. 我在C中编写一个队列结构,它接受字符串(char指针)作为元素。 The problem I'm having is that after printing the element value once, it comes out null afterwards. 我遇到的问题是,在打印元素值一次后,它会在之后出现null。

With the code below, I am expecting this output: 使用下面的代码,我期待这个输出:

1 Hello
1 Hello
2 World
Hello World
1

But I am getting this output: 但我得到这个输出:

1 Hello
1 (null)
2 World
(null) (null)
1

Can someone enlighten me on what I'm doing wrong? 有人可以告诉我我做错了什么吗?

#include <stdlib.h>
#include <stdio.h>

struct Node {
    struct Node *next;
    char* element; 
};
struct Queue {
    int size;
    struct Node *head;
    struct Node *tail;

};

void Enqueue(struct Queue *q, char* str) {
    struct Node newNode = {0,str};
    if(q->size == 0) {
        q->head = &newNode;
    }
    else {
        q->tail->next = &newNode;   
    }
    q->tail = &newNode;
    q->size = q->size + 1;
}
char* Dequeue(struct Queue *q) {
    if(q->size < 0) {   
        return -1;
    }
    char* tbr = q->head->element;
    struct Node* oldNode = q->head;
    q->head = oldNode->next;
    q->size = q->size - 1;
    if(q->size == 0) {
        q->tail = NULL;
    }
    return tbr;
}
int IsEmpty(struct Queue *q) {
    return q->size == 0;
}
char* Peek(struct Queue *q) {
    return q->head->element;
}
int main() {
    struct Queue q = {0};
    Enqueue(&q,"Hello");
    printf("%d %s\n",q.size,q.head->element);
    printf("%d %s\n",q.size,q.head->element);
    Enqueue(&q,"World");
    printf("%d %s\n",q.size,q.head->next->element);
    printf("%s %s\n",Dequeue(&q),Dequeue(&q));
    printf("%d\n",IsEmpty(&q));
    printf("%s %s\n","Hello","World");
    Dequeue(&q);
    return 0;
}

Enqueue() inserts references to memory on the stack, which is valid only locally: Enqueue()插入对堆栈内存的引用,该引用仅在本地有效:

void Enqueue(struct Queue *q, char* str) {
  struct Node newNode = {0,str}; 

As soon as the function returns this storage is freed, and accessing provoke undefine behaviour. 一旦函数返回,该存储就被释放,并且访问会激活undefine行为。

To resolve this dynamically allocate memory from the heap: 要解决此问题,请从堆中动态分配内存:

void Enqueue(struct Queue *q, char* str) {
  struct Node * pnewNode = calloc(1, sizeof(*pnewNode);
  if (NULL == pnewNode)
  {
    perror("calloc() failed");
    exit(EXIT_FAILURE);
  } 

  pnewNode->element = str;

  if(q->size == 0) {
    q->head = pnewNode;
  }
  else {
    q->tail->next = pnewNode;   
  }
  q->tail = pnewNode;
  q->size = q->size + 1;
}

Note that dynamically allocated memory needs to be free() ed. 请注意,动态分配的内存需要是free() ed。

Inside Enqueue , you can't use a local variable to insert a new node in the queue, because you're going to be using it outside of the function's lifetime, and local variables are destroyed after the function returns. Enqueue内部,您不能使用局部变量在队列中插入新节点,因为您将在函数的生命周期之外使用它,并且在函数返回后会破坏局部变量。

Thus, when you come back from Enqueue , the element inserted ( newNode ) points to an invalid memory location which will most likely be overwritten when you call another function. 因此,当您从Enqueue返回时,插入的元素( newNode )指向一个无效的内存位置,当您调用另一个函数时,该位置很可能会被覆盖。 All bets are off. 所有赌注都已关闭。 You must use dynamic allocation if you want your nodes to live longer: 如果希望节点寿命更长,则必须使用动态分配:

void Enqueue(struct Queue *q, char* str) {
    struct Node *newNode = malloc(sizeof(struct Node));
    newNode->next = NULL;
    newNode->element = str;
    if(q->size == 0) {
        q->head = newNode;
    }
    else {
        q->tail->next = newNode;   
    }
    q->tail = newNode;
    q->size = q->size + 1;
}

Also, note that now you need to free a node when you dequeue it. 另请注意,现在您需要在出列节点时free节点。 Dequeue becomes: Dequeue成为:

char* Dequeue(struct Queue *q) {
    if(q->size < 0) {   
        return -1;
    }
    char* tbr = q->head->element;
    struct Node* oldNode = q->head;
    q->head = oldNode->next;
    q->size = q->size - 1;
    if(q->size == 0) {
        q->tail = NULL;
    }
    free(oldNode);
    return tbr;
}

Inside main , your final Dequeue will cause a segmentation fault, because the queue is empty, and you don't check for this case in Dequeue . main内部,您的最终Dequeue将导致分段错误,因为队列为空,并且您不在Dequeue检查此情况。 Either you don't call Dequeue when IsEmpty returns true, or you add code to check for this case in Dequeue . 要么在IsEmpty返回true时不调用Dequeue ,要么在Dequeue添加代码以检查此情况。

Final note: in main , this line: 最后的说明: main是这一行:

printf("%s %s\n",Dequeue(&q),Dequeue(&q));

Will not necessarily print Hello World , because arguments evaluation order is implementation defined. 不一定会打印Hello World ,因为参数评估顺序是实现定义的。 In my machine, for example, it prints World Hello . 例如,在我的机器中,它打印World Hello

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM