链表-获取分段错误

Linked list- getting segmentation fault

void AlternatingSplit(struct Node* source, struct Node** aRef, 
                        struct Node** bRef) 
{
/* split the nodes of source to these 'a' and 'b' lists */
struct Node* a ; 
struct Node* b;

struct Node* current = source;
if(current){
    a=current;
    b=current->next;
    current=b->next;
    a->next=NULL;
    b->next=NULL;
}

while(current) {    
    a->next=current;
    b->next=current->next;

    if(b)
        current=b->next;

    b=b->next;
    a=a->next;
}

*aRef = a;
*bRef = b;
}

我在这里遇到分段错误,我不知道为什么请帮忙。

本题是交替拆分链表节点。我正在使用两个指针 a 和 b 并交替添加到它但它给出错误。请帮助我

您的代码中几乎没有错误 -

  • 试图访问 node->next ,而不检查节点是否存在。
  • 不根据链表的长度处理极端情况(即如果长度(链表)< 3)
  • 然后错误来了,你正在尝试创建新的链表,然后最后将 aRef 和 bRef 分配给各自链表中的最后一个节点。

尝试处理这些问题,您可以参考下面的代码。

void AlternatingSplit(struct Node* source, struct Node** aRef, 
                    struct Node** bRef) 
{

struct Node* a,b; 
struct Node* current = source;

if(current){
       a=current;
       b=current->next;
       // moving 'current' one step at a time will secure the code from crashing for corner cases
       current = current->next;
       if(b)
             current=b->next;
       a->next=NULL;
       b->next=NULL;

       //link aRef bRef right here
       *aRef = a;
       *bRef = b;
       }

 else {
      *aRef = source; // Null
      *bRef = source; // Null
      return;
      }

while(current) 
{
     a->next=current;
     a=a->next;
     b->next=current->next;
     b=b->next;
     current=current->next;
     if(b){
          current = b->next;
          }
 }
 b->next = NULL;
 a->next = NULL;

} 

希望这会有所帮助。

不断提问,不断成长:)

与大多数链表重排练习一样,指向指针的指针使工作变得容易得多。这个练习的目的是展示你改变 next 指针的能力,而不用改变 said-same 的数据值。指向指针的指针是在 C 中执行此操作的绝佳方式。

这特别简单,因为您已经为您提供了目标指针到指针的参数,我们可以重复使用这些参数来构建每个列表。通过演示使用单个头指针和指向指针 p:

的指针构建前向链表的技术,可以最好地理解其工作原理
struct Node *head, **pp = &head;
for (int i = 1; i <= 20; ++i)
{
    *pp = malloc(sizeof **pp);
    (*pp)->data = i;
    pp = &(*pp)->next;
}
*pp = NULL;

是的,它需要错误检查,但算法是这里关注的重点。此代码仅使用 pp 来构建实际列表。规则是这样的:pp 是指向 Node 的指针,而 总是 保存下一个要填充的 Node 指针的地址。这就是指向指针的指针所做的:保存指针的地址。在这种情况下 pp 最初保存头指针的地址。添加每个新节点后,pp 获取先前刚刚添加的节点的 next 指针的地址。有道理,对吧?那将是我们要挂起下一个节点的下一个指针。这个过程一直持续到我们完成循环。在该指针 pp 保存 last 节点的 next 指针的地址,我们将其设置为 NULL 以终止列表。

现在,了解我们上面学到的知识,考虑一下:

void AlternatingSplit(struct Node* source, struct Node** a, struct Node** b)
{
    while (source)
    {
        *a = source;
        a = &(*a)->next;

        source = source->next;
        if (source)
        {
            *b = source;
            b = &(*b)->next;
            source = source->next;
        }
    }

    *a = *b = NULL;
}

例子

下面显示了一个使用我首先展示的前向链接构建算法和我之后展示的拆分算法的简短示例。包括一些用于打印列表的实用函数。我把释放列表(现在有两个,记得遍历两个并释放每个节点)作为练习给你:

#include <stdio.h>
#include <stdlib.h>

struct Node
{
    int data;
    struct Node *next;
};

void AlternatingSplit(struct Node* source, struct Node** a, struct Node** b)
{
    while (source)
    {
        *a = source;
        a = &(*a)->next;

        if ((source = source->next))
        {
            *b = source;
            b = &(*b)->next;
            source = source->next;
        }
    }

    *a = *b = NULL;
}

void PrintList(struct Node const *p)
{
    while (p)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    fputc('\n', stdout);
}


int main(void)
{
    struct Node *head, **pp = &head;
    for (int i = 1; i <= 20; ++i)
    {
        *pp = malloc(sizeof **pp);
        (*pp)->data = i;
        pp = &(*pp)->next;
    }
    *pp = NULL;

    PrintList(head);

    struct Node *a = NULL, *b = NULL;
    AlternatingSplit(head, &a, &b);

    PrintList(a);
    PrintList(b);

    return EXIT_SUCCESS;
}

输出

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 3 5 7 9 11 13 15 17 19
2 4 6 8 10 12 14 16 18 20