我已经在CSC课程的实验室工作了一段时间,不幸的是我对C有点生疏(你可能会从代码中注意到)。我遇到了两个与内存管理有关的特殊问题。
1)在dequeue操作中,我试图从队列末尾的节点返回一个字符串值。因为我还试图使用free()并在检索数据后终止该节点,所以我需要使用类似strcpy()的方法来获取数据。每当我尝试使用strcpy时,程序会出现段错误,而Valgrind声称无效的r / w。
2)dequeue也没有正确更新stringQueue结构,原因我无法理解。我有类似的堆栈代码,其中的更改仍然存在,但我可以整天继续运行,并且实际上不会删除结束节点。
相关代码:
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;
}
答案 0 :(得分:1)
你的主要问题是像data = (queue->head)->data;
这样的行。你不能像这样分配数组。你应该memcpy
。 (strcpy
用于以空字符结尾的字符串,我猜它不是这样)
编辑:您也可以使用strncpy
,以避免缓冲区溢出。
答案 1 :(得分:0)
您可能希望首先将data
声明为char * = NULL
。然后,当您想要返回时,请使用data = asprintf("%s", (queue->tail)->data);
。这只会在需要时进行字符串分配和复制,并且只需要大小。然后,您的主叫代码必须承担责任以释放该数据本身。
您当前在堆内存中的节点结构中有char[]
。稍后,您将设置指向结构的data
成员的指针,然后在内存中释放结构。你留下了一个“悬垂指针”,指向结构曾经的位置。试图使用该指针将以几乎某些厄运结束(或更糟糕的是,不可预测的行为)。
答案 2 :(得分:0)
我发现您的代码存在一些问题......
首先,您不测试您的queue
参数不是NULL
。然后你还没有包含empty()
的定义,但可能测试queue-> head为NULL应该告诉你列表是空的。在你测试它是一个有效的指针之前,你在这里取消引用它,非常危险。
其次,您正在使用一些未正确使用的数据。当您执行感情data = (queue->head)->next;
时,您正在丢失指向已分配内存的指针,您可能希望在此处strncpy()
执行strncpy(data, queue->head->data, strMax)
。在此之后,您可以取消注释free()
。调用你的dequeue函数的函数将在以后不再使用时将free()
该字符串。
为什么不在您确定列表不为空时才分配data
?如果您不想这样做,那么您必须free()
不要使用malloc内存。
请参阅下面的代码。
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
且未指向自身。