Estoy aprendiendo la estructura de datos de LinkList, y ya he implementado el código fuente que funciona para mí. Hoy trato de hacerlo de otra manera como a continuación. Y estoy confundiendo por qué el programa se bloqueará aunque obtenga el resultado que quiero.

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

#define OK 1
#define ERROR 0

typedef int ElemType;
typedef int Status;

typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode, LinkList;   //I don't use the *LinkList on purpose to check it out

//Initialize LinkList: Create a head node
Status InitList(LinkList *L)
{
    L = malloc(sizeof(LinkList));
    if(!L) return ERROR;
    L->next = NULL;

    return OK;
}

//CreateList
Status CreateListHead(LinkList *L, int n)
{
    LinkList *s;
    int i;

    if(n < 1) return ERROR;
    InitList(L);
    srand(time(0));

    for(i=0; i<n; i++)
    {
        s = malloc(sizeof(LinkList));
        if(!s)  return ERROR;
        s->data = rand()%10+1;
        s->next = L->next;
        L->next = s;
    }

    return OK;
}

//Travese LinkList
void Traverse(LinkList *L)
{
    while(L->next)
    {
        printf("%d ", L->next->data);
        L->next = L->next->next;
    }
}

int main()
{
    LinkList *L;
    int s;

    s = InitList(L);
    if(s) printf("Successful!");
    else printf("Failed!");

    CreateListHead(L, 10);

    Traverse(L);
    return 0;
}

Y el resultado es: ¡Exitoso! 1 6 4 6 1 1 8 2 8 2 Y luego el programa se bloquea

2
s ange 10 may. 2019 a las 08:28

3 respuestas

La mejor respuesta

El problema aquí es que cualquier memoria que asigne a L dentro de InitList(), no se reflejará de nuevo en el argumento real pasado a la función cuando se llama.

Entonces, en tu código

if(n < 1) return ERROR;
InitList(L);               ----------------(1)
srand(time(0));

for(i=0; i<n; i++)
{
    s = malloc(sizeof(LinkList));
    if(!s)  return ERROR;
    s->data = rand()%10+1;
    s->next = L->next; -------------------(2)
    L->next = s;
}

En el punto (2), L aún no se ha inicializado. Acceder a eso invocará comportamiento indefinido.

C usa paso por valor, por lo que si tiene que modificar el argumento en sí , debe pasar un puntero a eso. Algo como

InitList(&L);

Y entonces,

Status InitList(LinkList **L)
{
    *L = malloc(sizeof(**L));
    if(!*L) return ERROR;
    (*L)->next = NULL;

    return OK;
}

Debería hacer el trabajo.

2
Sourav Ghosh 10 may. 2019 a las 05:47

El problema es que InitList inicializa una copia local de L, pero no el L que está en su función main. Cámbielo a InitList(LinkList **L) y llame como InitList(&L);, y cambie su implementación en consecuencia.

1
Ali Tavakol 10 may. 2019 a las 05:38

En realidad, estoy bastante sorprendido de que funcione en su máquina en primer lugar. (Es lo que técnicamente se conoce como comportamiento indefinido y puede manifestarse de varias maneras, incluyendo no síntomas visibles).

De todos modos, un problema inmediato está en InitList: cuando configura L allí, el puntero recientemente asignado no se propaga de regreso a la persona que llama. Para eso necesitas convertirlo en un puntero a puntero:

Status InitList(LinkList **L)
{
    *L = malloc(sizeof(LinkList));
    if(!*L) return ERROR;
    (*L)->next = NULL;

    return OK;
}

Luego deberá llamarlo así:

InitList(&L);
0
NPE 10 may. 2019 a las 05:33