2015-05-22 3 views
3

Почему возникает ошибка сегментации в этом коде?Добавить упорядоченный элемент рекурсивно

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)); 
} 

Проблема, кажется, когда я делаю * к = * ли, они являются указателями того же типа, Lint.

Это структура данных:

typedef struct slist *Lint; 

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

Идея о * к, чтобы перейти к предыдущему узлу следующего рекурсивного вызова, так что я могу связать эту старую структуру к новым и новый к следующему.

EDIT:

это полный код:

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; 
} 
+0

Если вы желая перестроить список, поскольку стек отключается, вам придется возвращать значение (узел). – ChiefTwoPencils

+0

Lint k = NULL; inserord (& list, 4, &k); ---> список не NULL, только k – skills

+1

Итак, что такое '& list'? Http://stackoverflow.com/help/mcve –

ответ

3

Вы можете написать функцию проще следующим образом

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; 
} 

и назвать его как

Lint listinha = NULL; 

listinha = inserord(listinha, 1); 

Если использовать подход, то функция может быть записана следующим образом (я использовал мой собственный переменные имена, потому что это легко для меня)

#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 

Или, если вы хотите, чтобы вызвать ее с третьим параметром, как указатель на то 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); 
} 

и называться как

struct Nodo *head = NULL; 
struct Nodo *prev = NULL; 


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

Отлично! Имеет много смысла. Хотя хотелось бы знать, что происходит в моем коде, так как я расстраиваюсь. Но я думаю, иногда лучше обойти проблему и отпустить старое решение. – skills

+0

@skills См. Мое обновленное сообщение. –

+0

Примечание: рассмотрим 'Lint new_li = malloc (sizeof * new_li);'. Никаких вопросов не требовалось, чтобы был запрошен правильный размер, лучше скрывать информацию, проще поддерживать. – chux

1

ошибка может быть случай * Ли NULL. Действительно, вы проверяете это, но вы делаете это только после проверки ((*li)->value) > x), который будет расширен до (NULL->value > x), который будет segfault.

Что вам нужно сделать, это просто поменять местами, если/иначе, если, например:

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)); 

} 

Segfault также может возникнуть при попытке получить доступ к (*k)->next, который будет в сегментации случае * K является NULL.

Предоставьте основной или некоторый фрагмент кода, в котором вы фактически называете inserord декларацией как li, так и k.

+0

К сожалению, они, похоже, знают, что '* li' * не' null'? – ChiefTwoPencils

+0

это не NULL действительно, код по-прежнему приводит меня к ошибке сегментации. – skills

+0

Я отредактировал ответ, добавив часть (* k) -> next. Благодарим за предоставление вашего основного. Я смотрю на это прямо сейчас. – cfz42

Смежные вопросы