链表获取分段错误

时间:2018-07-21 03:13:49

标签: c linked-list singly-linked-list

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并交替添加它,但是给出了错误。请帮助我

2 个答案:

答案 0 :(得分:2)

像大多数链表重排练习一样,指向指针的指针使工作变得非常简单。本练习的目的在于,您可以灵活地更改next指针,而无需更改相同的数据值。指向指针的指针是用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;
}

示例

下面显示了一个简短的示例,该示例同时使用了我首先显示的正向链构建算法和我之后显示的split算法。包括一些用于打印列表的实用程序功能。我将释放这些列表(现在有两个列表,请记住同时走路并释放每个节点)作为练习:

#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

答案 1 :(得分:1)

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

  • 尝试访问node-> next,而不检查节点是否存在。
  • 不根据链接列表的长度处理极端情况(即,如果length(链接列表)<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;

} 

希望这会有所帮助。

继续提问,保持成长:)