尝试从C/free问题中的队列返回字符串



我在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,并且不指向它自己。

相关内容

  • 没有找到相关文章