【问题标题】:Search linked list by substring and create a new linkedlist with all structs that contain the substring按子字符串搜索链表并创建一个包含所有包含该子字符串的结构的新链表
【发布时间】:2017-03-05 17:05:26
【问题描述】:

假设我有以下结构:

struct _node {
    int id;
    char *name;
    struct node *next;
};

我想编写一个函数,它遍历链表并查找名称成员包含某个子字符串的结构,并将这些结构添加到新的链表并返回新的链表。

我尝试使用 strstr 执行此操作,但在某些时候我遇到了无限循环,我无法弄清楚为什么会发生无限循环。

这是我的功能:

struct _node *containSubstr(struct _node *head, char needle[]) {
    if (head == NULL) {
        printf("BLOOP BLEEP BOOP BEEP.\n");
        exit(EXIT_FAILURE);
    }

    struct _node *curr = head;
    struct _node *returnHead = createEmptyNode();

    while (curr != NULL) {
        char haystack[strlen(curr->name)];
        strcpy(haystack, curr->name);

        strToLower(needle);
        strToLower(haystack);

        if (strstr(haystack, needle) != NULL) {
            // this is where I get the infinite loop
            append(returnHead, curr);
        }

        curr = curr->next;
    }

    return returnHead;
}

函数 append 和 createEmptyNode 已经过测试并且工作正常。

我多次检查了这个逻辑,我认为这必须有效。我用打印语句填充了我的代码,似乎在它找到包含子字符串的所有节点之后它不断重复最后一个节点并进入无限循环。

这是我的附加功能:

void append(struct _node *head, struct _node *newNode) {
    if (head == NULL) {
        printf("BLOOP BLEEP BOOP BEEP.\n");
        exit(EXIT_FAILURE);
    }

    struct _node *curr = head;

    if(curr == NULL) {
        head = newNode;
    }
    else {
        while(curr->next != NULL) {
            curr = curr->next;
        }
        curr->next = newNode;
    }
}

【问题讨论】:

  • The C library function size_t strlen(const char *str) computes the length of the string str up to, but not including the terminating null character.
  • 我修复了这个问题,但仍然出现无限循环。
  • 你的最后一个元素是否指向null,这是下一个明显的问题。
  • 显示你的createEmptyNode
  • append 函数中,第二个if 语句永远不会执行。

标签: c string linked-list


【解决方案1】:

想象一下这种情况:您有一个列表 L,它在您的链表中只包含 2 个节点(AB)。想象一下,两个节点 AB 都包含您要查找的子字符串:

原始列表L

A->B->NULL

所以在第一次迭代之后,您的新列表 L2 应该如下所示:

A->NULL

但是在您的附加函数中,您不会创建新节点的深层副本。因此,您的新列表 L2 如下所示:

Empty_node->A->B->NULL

在下一步中,您将移动到节点 B。所以你把你的L2 附加到那里B。第二次迭代后您的 L2 如下所示:

Empty_node->A->B->B(B指向自己)。

由于您不创建深层副本,因此您实际上一直在使用列表 L 并且当您将节点 B 附加到您认为的列表 L2 时 你实际上将 B 附加到 L,然后 B 指向它自己(append 函数中的curr->next = newNode;)。因此,在下一次迭代中,您再次询问 B 是否包含您要查找的字符串。

结论

创建新列表时需要创建深拷贝。

在当前设置中,您的 append 函数会修改原始列表。

【讨论】:

  • 嗨,这对我来说很有意义。您能否详细说明一下。如何初始化新列表?我怎样才能使它深入?目前我只是 mallocing 它然后将它的成员设置为 NULL。
  • 节点的深拷贝意味着您创建一个新节点,其中包含与原始节点完全相同的值。所以为一个节点分配内存,在这个节点内为name分配内存,然后将值从原始节点复制到新节点。
  • 我将 curr 节点复制到一个新节点中,并在追加之前对其进行了 malloc,它神奇地起作用了。还是不明白为什么。其他一切都完全相同。
  • @user6005857 我很高兴它可以工作,但您应该尝试了解您的原始代码有什么问题。一开始,您可以以某种方式打印您的链接列表(原始链接列表和应该只包含所需节点的链接列表),以查看每次迭代后它的外观。我希望我能解释得更好。
猜你喜欢
  • 1970-01-01
  • 2023-02-02
  • 2014-11-24
  • 1970-01-01
  • 2013-08-14
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2014-03-23
相关资源
最近更新 更多