Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 递归添加有序元素_C_Recursion - Fatal编程技术网

C 递归添加有序元素

C 递归添加有序元素,c,recursion,C,Recursion,为什么我会在这段代码中出现分段错误 void inserord(Lint *li, int x, Lint *k){ if(((*li)->value) > x){ Lint New; New = (Lint) calloc(1,sizeof(Nodo)); New->value= x; New->next = (*li); (*k)->next = New;

为什么我会在这段代码中出现分段错误

void inserord(Lint *li, int x, Lint *k){

    if(((*li)->value) > x){
        Lint New;
        New = (Lint) calloc(1,sizeof(Nodo));
        New->value= x;
        New->next = (*li);
        (*k)->next = New;
        return;

    }else if(*li == NULL){
        return;
    }
    *k = *li;
    inserord( &((*li)->next), x, &(*k));
}
问题似乎是当我使用*k=*li时,它们是相同类型的指针,Lint

这是数据结构:

typedef struct slist *Lint;

typedef struct slist {
    int value;
    Lint next;
} Nodo;
*k的思想是将上一个节点传递给下一个递归调用,这样我就可以将这个旧结构链接到新结构,将新结构链接到下一个

编辑:

这是完整的代码:

typedef struct slist *Lint;

typedef struct slist {
    int value;
    Lint next;
} Nodo;

void inserord(Lint *li, int x, Lint *k){
    if(((*li)->value) > x){
        Lint New;
        New = (Lint) calloc(1,sizeof(Nodo));
        New->value= x;
        New->next = (*li);
        (*k)->next = New;
        return;

    }else if(*li == NULL){
        return;
    }
    *k = *li;
    inserord( &((*li)->next), x, &(*k));
}

void insertend(Lint *l, int x){
    Lint new, aux;

    new = (Lint) calloc(1,sizeof(Nodo));
    new->value = x;
    new->next = NULL;

    if(*l==NULL){
        *l=new;
        return;
    }
    else
    {
        for(aux=*l; aux!=NULL ; aux = aux->next){
            if(aux->next == NULL){
                aux->next = new;
                return;
            }
        }
    }
}

int main(){
    Lint listinha;

    printf("\n");

    insertend(&listinha, 1);
    insertend(&listinha, 2);
    insertend(&listinha, 3);
    insertend(&listinha, 4);
    insertend(&listinha, 5);
    insertend(&listinha, 7);

    listVal(&listinha);

    Lint k = NULL;

    inserord(&listinha, 4, &k);

    listVal(&listinha);

    return 0;
} 

该错误可能是在*li为空的情况下发生的。实际上,您可以对它进行测试,但只有在检查
((*li)->value)>x)
后才能进行测试,这将扩展为
(NULL->value>x)
,这将导致故障

您需要做的是简单地交换if/else if,如下所示:

void inserord(Lint *li, int x, Lint *k){

/* This check must be done before attempting any other attempt to dereference (*li) */
if(*li == NULL){
    return;
}
else if(((*li)->value) > x){
    Lint New;
    New = (Lint) calloc(1,sizeof(Nodo));
    New->value= x;
    New->next = (*li);
    (*k)->next = New;
    return;

}
*k = *li;
inserord( &((*li)->next), x, &(*k));

}
在尝试访问
(*k)->next
时也可能发生SEGFULT,如果*k为空,则会出现SEGFULT


请提供一个main或某个片段,在其中您实际调用inserord,并声明
li
k

您可以用以下方法编写更简单的函数

Lint inserord( Lint li, int x )
{
    if ( ( li == NULL ) || !( li->value < x ) )
    {
        Lint new_li = malloc( sizeof( Nodo ) );
        new_li->value = x;
        new_li->next = li;

        return new_li;
    }

    li->next = inserord( li->next, x );

    return li;
}
如果使用您的方法,那么函数可以按以下方式编写(我使用自己的变量名,因为这对我来说很容易)

或者,如果希望使用第三个参数(如指向NULL的指针)调用它,那么函数可以如下所示

void inserord( struct Nodo **current, int x, struct Nodo **prev )
{
    if ( ( *current == NULL ) || !( ( *current )->value < x ) )
    {
        struct Nodo *nodo = malloc( sizeof( struct Nodo ) );

        nodo->value = x;
        nodo->next = *current;

        if ( *prev == NULL ) *current = nodo;
            //   ^^^^^^^^^^^^^ 
        else ( *prev )->next = nodo;

        return;
    }

    prev = current;
    current = &( *current )->next;

    inserord( current, x, prev );
}

如果要在堆栈展开时重建列表,则必须返回一个值(node);插入错误(&list,4,&k);-->列表不是空的,只有kSo什么是
&list
?是指向结构的指针,k和list是指向结构的指针请举例说明传递到该函数的
Lint
,以及它包含的内容,以便有人可以在需要时运行它并重现问题。此外,如果“这样我可以将旧结构与新结构联系起来,将新结构与新结构联系起来”是主要目标,那么您可能需要重新考虑您的方法。递归的好处是它将返回到第i个调用,这就是你如何将新旧链接的方式。不幸的是,他们似乎知道
*li
*不是
null
?它不是null。事实上,代码仍然会导致分段错误。我编辑了答案,添加了关于(*k)->下一步的部分。感谢您提供的主要信息。我现在正在查看它。@clement\u frndz如果函数通过条件if(*li==NULL)立即退出,您将如何在空列表中插入新值{return;?@VladfromMoscow确实,我的解决方案不提供此功能,但op的也不提供此功能。我对您的解决方案进行了优化,它实际上似乎符合op的需要。但请注意否定,li->value>x!(li->value<=x)。lldb告诉我您的程序在这一行上收到了SEGFULT:if(aux->next==NULL)在你的插入函数中,做得很好!非常有意义。虽然我想知道我的代码中发生了什么,但我觉得它很令人沮丧。但是我想有时候最好绕过一个问题,放开旧的解决方案。注意:考虑<代码>;。毫无疑问,要求的大小正确,信息隐藏更好,维护更容易。
#include <stdio.h>
#include <stdlib.h>

struct Nodo
{
    int value;
    struct Nodo *next;
};

void inserord( struct Nodo **current, int x, struct Nodo **prev )
{
    if ( ( *current == NULL ) || !( ( *current )->value < x ) )
    {
        struct Nodo *nodo = malloc( sizeof( struct Nodo ) );

        nodo->value = x;
        nodo->next = *current;

        if ( *prev == *current ) *current = nodo;
        else ( *prev )->next = nodo;

        return;
    }

    prev = current;
    current = &( *current )->next;

    inserord( current, x, prev );
}

void display( struct Nodo *current )
{
    for ( ; current != NULL; current = current->next )
    {
        printf( "%d ", current->value );
    }
}

int main(void) 
{
    struct Nodo *head = NULL;

    for ( int i = 10; i != 0;  ) inserord( &head, --i, &head );

    display( head );
    printf( "\n" );

    return 0;
}
0 1 2 3 4 5 6 7 8 9 
void inserord( struct Nodo **current, int x, struct Nodo **prev )
{
    if ( ( *current == NULL ) || !( ( *current )->value < x ) )
    {
        struct Nodo *nodo = malloc( sizeof( struct Nodo ) );

        nodo->value = x;
        nodo->next = *current;

        if ( *prev == NULL ) *current = nodo;
            //   ^^^^^^^^^^^^^ 
        else ( *prev )->next = nodo;

        return;
    }

    prev = current;
    current = &( *current )->next;

    inserord( current, x, prev );
}
struct Nodo *head = NULL;
struct Nodo *prev = NULL;


for ( int i = 10; i != 0;  ) inserord( &head, --i, &prev );