Почему программа настолько хороша, что я получил правильный результат? - PullRequest
2 голосов
/ 10 мая 2019

Я изучаю структуру данных LinkList, и я уже реализовал исходный код, который работает для меня.Сегодня я пытаюсь сделать это по-другому, как показано ниже.И я путаюсь, почему программа потерпит крах, даже если я получу желаемый результат.

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

И результат: Успешный!1 6 4 6 1 1 8 2 8 2 А потом программа вылетела

Ответы [ 3 ]

2 голосов
/ 10 мая 2019

Проблема здесь в том, что память, которую вы выделите для L внутри InitList(), не будет отражена обратно к фактическому аргументу, переданному функции при вызове.

Итак, в вашемкод

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

в точке (2), L по-прежнему не инициализирован.При доступе к нему будет вызываться неопределенное поведение .

C использует передачу по значению, поэтому, если вам нужно изменить сам аргумент , вам нужно передать указатель натот.Что-то вроде

InitList(&L);

, а затем

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

    return OK;
}

должен выполнить эту работу.

1 голос
/ 10 мая 2019

Проблема в том, что InitList инициализирует локальную копию L, но не L, которая есть в вашей функции main. Измените его на InitList(LinkList **L) и назовите InitList(&L);, и соответственно измените вашу реализацию.

0 голосов
/ 10 мая 2019

Я на самом деле очень удивлен, что это происходит, прежде всего, на вашей машине. (Это то, что технически известно как неопределенное поведение и может проявляться различными способами, включая отсутствие видимых симптомов.)

В любом случае, одна немедленная проблема связана с InitList: когда вы устанавливаете L, вновь выделенный указатель не распространяется обратно на вызывающую сторону. Для этого вам нужно превратить его в указатель на указатель:

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

    return OK;
}

Затем вам нужно будет назвать это так:

InitList(&L);
...