【问题标题】:Merge values in two nodes of linked list合并链表的两个节点中的值
【发布时间】:2017-09-07 08:14:53
【问题描述】:

我有一个 squeue(堆栈和队列的组合)。我有一个名为 mergeFront 的函数,它的工作应该是将前两个节点合并为一个。例如,如果前面的节点是“alpha”,而第二个节点是“beta”,则它们应该合并到“alphabeta”中。

void mergeFront(struct Squeue* squeue){
    struct Node* temp;
    char *string;
    char *tempstring=malloc(sizeof(char)*100);
    temp = squeue->first;
    temp = temp->next;
    string = squeue->first->val;
    strcpy(tempstring, string);
    string = temp->val;
    strcat(tempstring, string);
    squeue->first->next->val=tempstring;
    temp = squeue->first;
    squeue->first = temp->next;
    free(temp);
    free(tempstring);
}

当我在最后一行free(tempstring) 时,第一个节点现在变为空(假设因为我已经释放了值所指向的内容)。如果我摆脱了free(tempstring),它运行良好,但存在内存泄漏。如何在正确释放内存的同时做到这一点?

节点结构如下

struct Node{
    char* val;
    struct Node* next;
    struct Node* prev;
};

获取@ikegami 给出的代码后,我的代码如下:

void mergeFront(struct Squeue* squeue){

  struct Node* node1 = squeue->first;  if (node1 == NULL) return;
  struct Node* node2 = node1->next;    if (node2 == NULL) return;

  char* str1 = node1->val;  size_t str1len = strlen(str1);
  char* str2 = node2->val;  size_t str2len = strlen(str2);
  char* merged = malloc(str1len + str2len + 1);
  memcpy(merged, str1,str1len + 1);
  strcpy(merged+str1len, str2);

  node1->val = NULL;
  free(node1->val);
  node1->val = merged;

  node1->next = node2->next;

  node2->val = NULL;
  free(node2->val);
  free(node2);

}

除了我仍然在 1 个块中获得 10 字节的泄漏内存外,它功能齐全。关于我在哪里可以找到这个的任何线索?

【问题讨论】:

  • 你可能想释放first->valfirst->next->val而不是tempstring指向的2个字符串。
  • 确实,不要免费tempstring!您仍在使用引用的内存。
  • ...当你释放它时,它绝对不会将任何指向它的指针设为 NULL——你必须自己做。这是 C,而不是一些手把手的初学者语言 :-)
  • 重新编辑:您不能将指针设置为NULL 之前free它!如果您觉得必须设置为NULL,请在free 之后进行。
  • node1->val = NULL; free(node1->val); 没有意义。和node1->val = NULL; 一样

标签: c stack queue nodes


【解决方案1】:
void mergeFront(struct Squeue* squeue) {
    /* Make sure we have at least two nodes. */
    struct Node* node1 = squeue->first;  if (node1 == NULL) return;
    struct Node* node2 = node1->next;    if (node2 == NULL) return;

    /* Create the combined string. */
    char* str1 = node1->val;  size_t str1len = strlen(str1);
    char* str2 = node2->val;  size_t str2len = strlen(str2);
    char* merged = malloc(str1len + str2len + 1);
    memcpy(merged, str1, str1len);
    strcpy(merged+str1len, str2);

    /* Replace the first node's string with the combined string. */
    free(node1->val);
    node1->val = merged;

    deleteNode(squeue, node2);
}

助手:

void deleteNode(struct Squeue* squeue, struct Node* node) {
    if (node->prev == NULL)
        squeue->first = node->next;
    else
        node->prev->next = node->next;

    if (node->next == NULL)
        squeue->last = node->prev;
    else
        node->next->prev = node->prev;

    free(node->val);
    free(node);       
}

注意事项:

  • 我没有释放tempstring(现在称为merged)指向的内存,因为它仍在使用(squeue->first->val)!
  • 不要猜测您需要多少内存!必要时计算一下。
  • * sizeof(char) 没用,因为 sizeof(char) 始终是 1
  • 上述代码需要 C99 支持,因为它混合了声明和代码。它可以很容易地转换为向后兼容的代码(以牺牲可读性为代价)。
  • 我使用了比我需要的更多的变量,希望使代码清晰。
  • 经过测试。

由于您将其称为“堆栈队列”,因此使用堆栈和队列操作会更有意义。

void mergeFront(struct Squeue* squeue) {
    struct Node* node1 = shift(squeue);
    if (node1 == NULL) {
        return;
    }

    struct Node* node2 = shift(squeue);
    if (node2 == NULL) {
        unshift(squeue, node1);
        return;
    }

    char* str1 = node1->val;  size_t str1len = strlen(str1);
    char* str2 = node2->val;  size_t str2len = strlen(str2);
    node1->val = realloc(node1->val, str1len + str2len + 1);
    strcpy(node1->val + str1len, node2->val);

    freeNode(node2);
    unshift(squeue, node1);
}

助手:

void freeNode(struct Node* node) {
    free(node->val);
    free(node);
}

struct Node* shift(struct Squeue* squeue) {
    struct Node* node = squeue->first;
    if (node == NULL)
        return NULL;

    squeue->first = node->next;
    if (node->next == NULL)
        squeue->last = NULL;
    else {
        node->next->prev = NULL;
        node->next = NULL;
    }

    return node;
}

struct Node* pop(struct Squeue* squeue) {
    struct Node* node = squeue->last;
    if (node == NULL)
        return NULL;

    squeue->last = node->prev;

    if (node->prev == NULL)
        squeue->first = NULL;
    else {
        node->prev->next = NULL;
        node->prev = NULL;
    }

    return node;
}

void unshift(struct Squeue* squeue, struct Node* node) {
    if (squeue->first == NULL) {
        squeue->first = node;
        squeue->last = node;
    } else {
        node->next = squeue->first;
        squeue->first = node;
    }
}

void push(struct Squeue* squeue, struct Node* node) {
    if (squeue->last == NULL) {
        squeue->first = node;
        squeue->last = node;
    } else {
        node->prev = squeue->last;
        squeue->last = node;
    }
}

经过测试。

【讨论】:

  • 我尝试使用 realloc 实现该解决方案,但是我遇到了段错误。在调试时,我相信它出现在 realloc 行中。你的 memcpy 也缺少最后一个参数......我相信它应该是 str1len + 1?
  • 经过一番挖掘。导致问题的是 free(node2->val) 。它没有错误:无效指针
  • 我没有我发布的 realloc 代码的副本,所以我无法发表评论。 (我意识到当程序耗尽内存时它会泄漏,所以我将其删除。然后,当程序耗尽内存时,发布的解决方案和 relalloc 解决方案都出现了段错误......) /// 修复了memcpy 行.无需复制将在一秒钟后被覆盖的 NUL。 /// free(node2->val) 应该在那里。也许node2 一开始就没有正确构建?
  • 刚刚意识到这是一个双链表。调整后的答案。
【解决方案2】:

这看起来很奇怪

squeue->first->next->val=tempstring;
temp = squeue->first;
squeue->first = temp->next;
free(temp);
free(tempstring);

首先你分配 tempstring 并分配一个指针 val 指向它,然后你释放它,使 val 指向无效。

看来你应该跳过free(tempstring)

为了合并两个节点。首先检查两个字符串的长度以分配足够的空间,而不是假设 100 就足够了。分配一个可以包含两个字符串和结尾 \0 的缓冲区,即在两个字符串上使用 strlen() 并添加一个 1。

然后将 strcpy/strcat 两个值都写入该缓冲区。

然后释放第一个和第二个节点指向的字符串

然后分配第一个节点指向这个新节点

然后设置指针在第一个节点消除第二个,不要忘记释放第二个节点。即每个节点有两个分配,一个分配给节点本身,一个分配给它持有的字符串。

【讨论】:

  • 这是我的问题!如果我删除了免费(临时字符串),那么我就会陷入内存泄漏。这就是我困惑的地方
【解决方案3】:

你想做什么:

  1. 为新字符串分配空间
  2. 将 2 个旧字符串合并到新字符串中
  3. 删除 2 个旧字符串
  4. 删除第一个节点,更新第一个节点
  5. 将新字符串分配给新的第一个节点

-

void mergeFront(struct Squeue* squeue){
    // Make sure there are at least 2 nodes
    if (NULL == squeue->first || NULL == squeue->first->next) {
        return;
    }

    // 1. Allocate space for the new string
    char *tempstring = malloc(strlen(squeue->first->val) +
                              strlen(squeue->first->next->val) + 1);
    if (NULL == tempstring) {
        // Out of memory
        return;
    }

    // 2. Merge the 2 old strings into the new string
    sprintf(tempstring, "%s%s", squeue->first->val, squeue->first->next->val);

    // 3. Delete the 2 old strings
    free(squeue->first->val);
    free(squeue->first->next->val);

    // 4. Delete the first node, and update first node
    struct Node* temp = squeue->first;
    squeue->first = squeue->first->next;
    squeue->first->prev = NULL;
    free(temp);

    // 5. Assign the new string to the new first node
    squeue->first->val = tempstring;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 2016-06-17
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多