0

我正在用 C 语言编写一个将字符串(字符指针)作为元素的队列结构。我遇到的问题是,在打印一次元素值之后,它就变成了 null 。

使用下面的代码,我期待这个输出:

1 Hello
1 Hello
2 World
Hello World
1

但我得到这个输出:

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

有人可以告诉我我做错了什么吗?

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

2 回答 2

1

在内部Enqueue,您不能使用局部变量在队列中插入新节点,因为您将在函数的生命周期之外使用它,并且局部变量在函数返回后被销毁。

因此,当您从 回来时Enqueue,插入的元素 ( newNode) 指向一个无效的内存位置,当您调用另一个函数时,该位置很可能会被覆盖。所有的赌注都取消了。如果您希望节点寿命更长,则必须使用动态分配:

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

另外,请注意,现在您在出列时需要free一个节点。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;
}

在里面main,你的 finalDequeue会导致分段错误,因为队列是空的,你没有在Dequeue. 要么在返回 trueDequeue时不调用,要么在.IsEmptyDequeue

最后注:在main,这一行:

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

不一定会 print Hello World,因为参数评估顺序是实现定义的。例如,在我的机器中,它打印World Hello.

于 2013-11-02T09:33:49.903 回答
1

Enqueue()在堆栈上插入对内存的引用,这仅在本地有效:

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

一旦函数返回,这个存储就会被释放,并且访问会引发未定义的行为。

要解决此问题,请从堆中动态分配内存:

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

请注意,需要free()编辑动态分配的内存。

于 2013-11-02T09:29:55.590 回答