简体   繁体   English

在屏幕上打印链接列表时程序崩溃

[英]Program crashes when printing a linked list on screen

I don't know why I can read the Linked list without problems in LABEL : 1 ; 我不知道为什么我可以在LABEL中没有问题地阅读链接列表:1; but the program just crashes and print grabage in the LABEL : 0 ; 但该程序只是在LABEL中崩溃并打印了垃圾:0; In other terms, why the linked list works fine inside the lecture function , but not outside it ? 换句话说,为什么链接列表在讲座功能中工作正常,但不在其外? Here is my code : 这是我的代码:

/* including libraries */
#define V 20

typedef struct DATA{
    char* NomP;char* NomA;
    struct DATA *Next;
}DATA;

// Prototypes .

int main(void)
{
    char FileName[V];
    puts("Data file ? : ");gets(FileName);

    FILE* fs = fopen(FileName,"r"); // Check if fs is NULL

    DATA *HEAD = MALLOC(sizeof (DATA)); int len = lecture_data(fs,HEAD);
    print_data(HEAD,len); //LABEL : 0
    return 0;
}

int lecture_data(FILE *fs,DATA *ROOT)
{
    char cNom[V],cArticle[V];
    int eofs=0;int i=0;

while(!eofs)
{
    DATA *Data = MALLOC(sizeof (DATA));
    fscanf(fs,"%s %s",cNom,cArticle);
    Data->NomA = MALLOC(strlen(cArticle)+1);
    Data->NomP = MALLOC(strlen(cNom)+1);
    strcpy(Data->NomA,cArticle);
    strcpy(Data->NomP,cNom);
    if( i==0 )
    {
        Data -> Next = NULL ;
        ROOT = Data ;
    }
    else
    {
        DATA* Ptr = ROOT ;
        while( (Ptr->Next) != NULL )
        {
            Ptr = (Ptr -> Next);
        }
        Data -> Next = NULL ;
        Ptr -> Next = Data ;
    }
    i++;
    eofs = feof(fs) ;
    // check ferror(fs) here
}
    puts("Start of reading :");

    print_data(ROOT,len); // LABEL : 1

    puts("End Of Reading ");
    fclose(fs);
    return i;
}

Here is the printing function : 这是打印功能:

void print_data(DATA *L_ROOT,int len)
{
    int i = 0 ;
    DATA* LINK;
    LINK = L_ROOT;
    while( LINK != NULL )
    {
        printf("%d : DATA->NomA : %s\n",i,LINK->NomA);
        printf("%d : DATA->NomP : %s\n",i,LINK->NomP);
        LINK = LINK -> Next ;
        i++;
    }
}

You're allocating data for the root of the list in the main function, and pass that to the function so that it may populate the list, but the first time you allocate an element you overwrite the ROOT pointer value. 您正在为main函数中的列表根分配数据,并将其传递给函数,以便它可以填充列表,但是第一次分配元素时会覆盖ROOT指针值。

this makes you lose the only connection between the function and the outside world (since the return value is just a number), so the HEAD value in main() is left pointing at nothing meaningful (because your function never uses it), while the list remains allocated in some memory location that no one outside is pointing to, which means it's lost. 这使你失去了函数和外部世界之间的唯一连接(因为返回值只是一个数字),所以main()中的HEAD值指向没有任何意义(因为你的函数从不使用它),而list仍然分配在某个内存位置,没有人指向外部,这意味着它丢失了。 Running valgrind would have been able to identify this. 运行valgrind本来可以识别这个。

You can fix that by changing the (i==0) case from - 您可以通过更改(i == 0)案例来解决这个问题 -

ROOT = Data ;

into

ROOT->next = Data ;

but make sure you're ignoring the data of the root node later on. 但请确保稍后忽略根节点的数据。

ps - using capitalized variables and types is not considered a good idea (it's mostly reserved for macros). ps - 使用大写变量和类型不被认为是一个好主意(它主要是为宏保留的)。 It also makes your code look like you're shouting :) 它也使你的代码看起来像你在喊:)

The (main) problem is that lecture_data doesn't use it's input parameter ( ROOT ) for storage of the linked list, nor does it return the internal generated list. (主要)问题是lecture_data不使用它的输入参数( ROOT )来存储链表,也不返回内部生成的列表。 The correct way to handle this is to have ROOT reference the calling scope's parameter so that it can update it's reference as necessary. 处理此问题的正确方法是让ROOT引用调用范围的参数,以便它可以根据需要更新它的引用。

int main(void)
{
    char FileName[V];
    puts("Data file ? : ");gets(FileName);

    FILE* fs = fopen(FileName,"r"); // Check if fs is NULL

    DATA *HEAD = NULL;
    int len = lecture_data(fs, &HEAD);
    print_data(HEAD); //LABEL : 0

    return 0;
}

int lecture_data(FILE *fs,DATA **ROOT)
{
    char cNom[V],cArticle[V];
    int i=0;
    DATA *current = *ROOT; // grab the passed in reference

    while(!feof(fs))
    {
        if(fscanf(fs,"%s %s",cNom,cArticle) <= 0) // This call is only successful if the return value is > 0
        {
            // check ferror(fs) here
            continue; // Can also "break;" here, essentially, it's eof already
        }

        DATA *Data = MALLOC(sizeof (DATA));
        Data->NomA = MALLOC(strlen(cArticle)+1);
        Data->NomP = MALLOC(strlen(cNom)+1);
        strcpy(Data->NomA,cArticle);
        strcpy(Data->NomP,cNom);

        if(NULL == current) // ROOT was uninitialized before the call
        {
            Data -> Next = NULL;
            *ROOT = Data;
        }
        else
        {   // We don't need to iterate the list in every step.
            Data->Next = current->Next; // This part allows the function to insert nodes in the middle / end of an existing list
            current->Next = Data;
            current = Data;
        }
        i++;
    }
    puts("Start of reading :");

    print_data(ROOT); // LABEL : 1

    puts("End Of Reading ");
    fclose(fs);
    return i;
}

Note: print_data didn't do anything with the len parameter, so no need passing it in at all. 注意: print_data没有对len参数做任何事情,因此根本不需要传入它。

This solution is not wasteful in terms of "empty" nodes in the list (as opposed to having an empty head to ignore), and is suitable both for initializing the list from scratch AND for cases where you need to append / insert into an existing list. 对于列表中的“空”节点而言,此解决方案并不浪费(而不是忽略空头),并且适用于从头开始初始化列表以及需要追加/插入现有列表的情况名单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM