我在C中编写一个队列结构,它接受字符串(char指针)作为元素。我遇到的问题是,在打印元素值一次后,它会在之后显示为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;
}
答案 0 :(得分:1)
Enqueue()
插入对堆栈内存的引用,该内存仅在本地有效:
void Enqueue(struct Queue *q, char* str) {
struct Node newNode = {0,str};
一旦函数返回,该存储就被释放,并且访问会激活undefine行为。
要解决此问题,请从堆中动态分配内存:
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()
ed。
答案 1 :(得分: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
内,您的最终Dequeue
会导致分段错误,因为队列为空,并且您不会在Dequeue
中检查此情况。您可以在Dequeue
返回true时不致电IsEmpty
,或者在Dequeue
中添加代码以检查此案例。
最后注意事项:在main
中,此行:
printf("%s %s\n",Dequeue(&q),Dequeue(&q));
不一定会打印Hello World
,因为参数评估顺序是实现定义的。例如,在我的机器中,它会打印World Hello
。