我在CSC类的实验室工作了一段时间,不幸的是,我对C有点生疏(您可能会从代码中注意到)。我遇到了两个特别的问题,都与内存管理有关。
1) 在出列操作中,我试图从队列末尾的节点返回一个字符串值。由于我还试图使用free()并在检索数据后杀死该节点,因此我需要使用strcpy()这样的方法来获取数据。每当我尝试使用strcpy时,程序都会出错,而Valgrind声称r/w无效。
2) dequeue也没有正确更新stringQueue结构,原因我无法理解。对于修改持续存在的堆栈,我有类似的代码,但我可以全天运行dequeue,它实际上不会删除结束节点。
相关代码:
typedef struct node {
char data [strMax];
struct node * next;
} queueNode;
typedef struct {
queueNode * head;
queueNode * tail;
} stringQueue;
char * dequeue(stringQueue *queue) {
char * data = malloc(strMax * sizeof(char));
if(empty(*queue)) {
return "Null list!";
}
else if(!(queue->head)->next) { // One item in the queue.
data = (queue->head)->data;
//free(queue->head);
queue->head = NULL;
queue->tail = NULL;
}
else { // Multiple items in the queue.
data = (queue->tail)->data;
free(queue->tail);
queueNode * trace = queue->head;
while(trace->next) // Seek the last node in the queue.
trace = trace->next;
queue->tail = trace;
}
return data;
}
您的主要问题出现在data = (queue->head)->data;
这样的行中。不能这样分配数组。您应该memcpy
。(strcpy
用于以null结尾的字符串,我想不是这样的)
edit:您也可以使用strncpy
,以避免缓冲区溢出。
您可能希望首先将data
声明为char * = NULL
。然后,当您想要返回它时,请使用data = asprintf("%s", (queue->tail)->data);
。这将只在需要时执行字符串分配和复制,并且只执行所需的大小。然后,您的调用代码必须负责释放数据本身。
您当前在堆内存中的节点结构中有一个char[]
。稍后,您将设置一个指向结构的data
成员的指针,然后释放内存中的结构。你只剩下一个指向结构过去所在位置的"悬空指针"。尝试使用该指针将以几乎肯定的厄运(或者更糟的是,不可预测的行为)告终。
我发现您的代码有一些问题。。。
首先,您不测试您的queue
参数不是NULL
。那么,您还没有包含empty()
的定义,但可能测试了queue->head为NULL会告诉您列表是空的。在这里,你在测试它是一个有效的指针之前取消引用它,非常危险。
其次,您正在对一些未正确使用的数据进行锦葵操作。当你做情感data = (queue->head)->next;
时,你失去了指向你分配的内存的指针,你可能想在这里做strncpy()
,就像strncpy(data, queue->head->data, strMax)
一样。在此之后,您可以取消对free()
的注释。调用出列一的函数稍后将不得不在不再使用该字符串时free()
。为什么不只在确定列表不是空的情况下分配data
?如果你不想这样做,那么你就必须free()
那个未编码的malloc’ed内存。
请参阅下面的代码。
queueNode* find_before_tail(stringQueue* queue)
{
queueNode* node = NULL;
if (!queue || !queue->head)
return NULL;
node = queue->head;
while (node->next != queue->tail && node->next)
node = node->next;
return node;
}
char * dequeue(stringQueue *queue) {
char *data = NULL;
queueNode* to_queue = NULL;
if(!queue || !queue->head) {
/* Nothing to dequeue here... */
return NULL;
}
data = malloc(strMax * sizeof(char));
if (!data) {
printf("Error with malloc()...n");
return NULL;
}
/* Only one element */
if(!(queue->head)->next == queue->head) {
strncpy(data, queue->head->data, strMax);
free(queue->head);
queue->head = NULL;
queue->tail = NULL;
}
else {
strncpy(data, queue->tail->data, strMax);
to_dequeue = queue->tail;
queue->head = queue->head->next;
queue->tail = find_before_tail(queue);
if (!queue->tail)
return NULL;
queue->tail->next = NULL;
free(to_dequeue);
}
data[strMax - 1] = 0;
return data;
}
从这一点来看,您的代码的其余部分可能还有一些其他问题,但希望它能为您提供一些基础。
使用您的队列代码编辑
在这里,您不是在测试malloc()
的返回值。这里有一个带有非循环链表的版本(我也更新了上面的dequeue()
函数来处理它)。
int enqueue(stringQueue *queue, char *item)
{
queueNode * newNode = NULL;
if (!queue || !item)
return EINVAL;
newNode = malloc(sizeof(queueNode));
if (!newNode) {
perror("malloc()");
return errno;
}
strncpy(newNode->data, item, strMax);
newNode->data[strMax - 1] = 0;
if (!queue->head) {
/* Element is queue and tail */
queue->tail = newNode;
}
newNode->next = queue->head;
queue->head = newNode;
return 0; /* Everything was fine */
}
我还没有测试过代码,但它应该与此非常相似。在这种情况下,当只有一个元素时,this_element->next
就是NULL
,并且不指向它自己。