尝试打印时,链接列表中的节点显示为空

时间:2014-06-01 11:09:26

标签: c list linked-list

所以,这就是事情。我有这个程序,它将不同的作者存储在链表中,每个作者都有自己的记录,每个记录都保存着他的文本,并在链表中组织。从文件中读取数据。这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

struct AuthorRecord
{
    char textTitle[100];
    int NumberOfWords;
    long Download;
    struct AuthorRecord *next;
};
typedef struct AuthorRecord *AuthorRecordType;

typedef struct
{
    char firstName[30];
    char lastName[30];
    int idNumber;
    int textNum;
    AuthorRecordType text;
} AuthorType;

struct MemberNodeStruct
{
    AuthorType *anAuthor;
    struct MemberNodeStruct *next;
};
typedef struct MemberNodeStruct *MemberNodeType;

FILE* input;
FILE* output;
MemberNodeType head;
MemberNodeType member;

int main (void)
{
    int authorNum, textNum, i, j;

    member = malloc(sizeof(struct MemberNodeStruct));
    head = member;
    member->next = NULL;

    input = fopen("input.txt", "r");
    if (input == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    fscanf(input, "%d", &authorNum);

    for (i = 0; i < authorNum; i++)
    {
        member->anAuthor = malloc(sizeof(AuthorType));
        textNum = 0;
        if(fscanf(input, "%s %s %d", member->anAuthor->lastName, member->anAuthor->firstName, &member->anAuthor->idNumber) != EOF)
        {
            fscanf(input, "%d", &member->anAuthor->textNum);

            for (j = 0; j < member->anAuthor->textNum; j++)
            {
                member->anAuthor->text = malloc(sizeof(struct AuthorRecord));

                fscanf(input, " %[^\n]", member->anAuthor->text->textTitle);
                fscanf(input, "%ld", &member->anAuthor->text->Download);


                member->anAuthor->text = member->anAuthor->text->next;
            }

            member->next = malloc(sizeof(MemberNodeType));
            member = member->next;
        }
        else
            member->next = NULL;
    }

    member = head;
    while(true)
    {
        if (member->next == NULL)
            break;
        for (i = 0; i < authorNum; i++)
        {
            printf("%s %s %d\n", member->anAuthor->lastName, member->anAuthor->firstName, member->anAuthor->idNumber);

            for (j = 0; j < member->anAuthor->textNum; j++)
            {
                printf("%s\n", member->anAuthor->text->textTitle);
                printf("%ld\n", member->anAuthor->text->Download);

                member->anAuthor->text = member->anAuthor->text->next;
            }
            member = member->next;
        }
    }
}

我已经通过gdb运行程序,一切都很好。但是,当我到达这一行printf("%s\n", member->anAuthor->text->textTitle);时,我得到了一个段错误。 显然member->anAuthor->text字段为空,其地址为0x0。 <{1}}和member上的数据和内存地址是正确的。

这里有什么问题?

2 个答案:

答案 0 :(得分:1)

当您阅读每位作者的文本时,您使用autor节点的text成员作为迭代器

        for (j = 0; j < member->anAuthor->textNum; j++)
        {
            member->anAuthor->text = malloc(sizeof(struct AuthorRecord));

            fscanf(input, " %[^\n]", member->anAuthor->text->textTitle);
            fscanf(input, "%ld", &member->anAuthor->text->Download);


            member->anAuthor->text = member->anAuthor->text->next;
        }

整个街区的逻辑是错误的。 text->next永远不会有有意义的价值,甚至不是NULL。并且文本没有链接,它们只是不相关的数据块,一旦循环遍历就无法访问。特别是,您必须先分配,然后将前一个链接的next指针设置为该内存。

文本列表的text指针应该与成员列表中的head类似,并且只能分配一次。 (在用NULL初始化之后,即。)

也就是说,代码中有各种"smells"

  • 结构非常可怕。我知道这是一个赋值,你的结构作为起点,但为什么文本节点与AuthorRecord明显不同时调用AutorType
  • 正如已经指出的那样,为结构体定义指针类型不会增加任何内容;它只会混淆,如果类型名为AuthorRecordType,而不是AuthorPtrPAuthor。在C中,星号标记指针类型;很难表现得那么富有表现力。 (另外,输入更容易。)
  • 使用额外成员跟踪列表中的条目数可能很有用,但列表的遍历应始终与列表结构本身(即next指针)一起使用,以避免可能的意外情况。
  • 当您向列表中添加元素时,请在需要内存时调用malloc,而不是提前。如果你在读取之前对第一个元素进行malloc,然后将其设置为NULL,因为事实证明你并不需要它,那么就会造成内存泄漏。
  • 完成后,每个malloc都需要free。 (我知道你的代码目前还不完整;只是说。)
  • 您的整个scanf序列需要进行错误检查。如果输入不正确,很容易进入无限循环。 (旁注:在此处发布一小段示例输入以帮助我们找到错误也很有帮助。)
  • 考虑创建小函数来创建每个类型,清理它们并将它们添加到列表中;不要把所有东西都放进main。将阅读与创建结构分开也是一个好主意。
  • 您使用如下所示的长序列成员引用:member->anAuthor->text->next。考虑使用临时指针。这将使引用更短(text->next),并希望代码更清晰。

答案 1 :(得分:0)

There are several items to note in your code, 
such as the definition of struct { fields }   name; is depreciated 
and should not be used in new code.
Rather use: struct name { fields };  
which does require using 'struct' wherever the structure name is referenced.

There are several logic errors in the code that are causing it to fail, 
such as not initializing the pointers to malloc'd areas to null.

Note: all the malloc'd areas need to be free'd at each exit point,
    without back links, the free processing will be time consuming
    Suggest adding a back link to each malloc'd area to simplify that operation

Also, the struct MemberNode is not needed
because a linked list of the struct AuthorType would contain all the relevant data.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

struct AuthorRecord
{
    char textTitle[100];
    int NumberOfWords;
    long Download;
    struct AuthorRecord *next;
};



struct AuthorType
{
    char firstName[30];
    char lastName[30];
    int idNumber;
    int textNum;
    struct AuthorRecord text;
};


struct MemberNode
{
    struct AuthorType *anAuthor;
    struct MemberNode *next;
};



FILE* input;

struct MemberNode *head = NULL; // head of linked list
struct MemberNode *member = NULL; // ptr to current item in linked list

int main (void)
{
    int authorNum, textNum, i, j;

    input = fopen("input.txt", "r");
    if (NULL == input)
    {
        perror("fopen(input.txt) %s", strerror(errno) );
        return (errno);
    }



    // read number of authors
    fscanf(input, "%d", &authorNum);

    // for each author
    for (i = 0; i < authorNum; i++)
    {
        // one of member struct per author
        if( NULL == member )
        { // first time
            member = (struct MemberNode*)malloc(sizeof(struct MemberNode));
            head = member;
            member->next = NULL; // initialize
        }
        else
        { // not first time
            // link to new member node
            member->next = (struct MemberNode*)malloc(sizeof(struct MemberNode);
            if( NULL == member->next ) 
            { 
                perror( "malloc(MemberNode) %s", strerror( errno ) );
                return(errno);
            }

            //memset( member->next, 0x00, sizeof(struct MemberNode) );
            member = member->next; // step to new member node
            member->anAuthor = NULL; // initialize ptr to author info list
            member->next = NULL; // initialize
        }

        // set secondary linked list member(author) & point to it
        member->anAuthor = (struct AuthorType*)malloc(sizeof(struct AuthorType));
        if( NULL == member->anAuthor ) 
        { 
            perror( "malloc(AuthorType) %s", strerror( errno ) );
            return(errno);
        }

        //memset( member->anAuthor, 0x00, sizeof(struct AuthorType) );
        member->anAuthor->next = NULL; // initialize
        member->anAuthor->text = NULL; // initialize

        // read a line of author info
        if(fscanf(input, "%s %s %d", 
            member->anAuthor->lastName, 
            member->anAuthor->firstName, 
            &(member->anAuthor->idNumber) ) != EOF)
        { // then, successful read of author info

            // read number of author titles
            fscanf(input, "%d", &(member->anAuthor->textNum));

            // for each author title
            for (j = 0; j < member->anAuthor->textNum; j++)
            {
                member->anAuthor->text = 
                    (struct AuthorRecord*)malloc(sizeof(struct AuthorRecord));
                if( NULL == member->anAuthor->text ) 
                { 
                    perror( "malloc(AuthorRecord) %s", strerror( errno ) );
                    return(errno);
                }

                //memset( member->anAuthor->text, 0x00, sizeof(struct AuthorRecord) );
                // step to new author/text record
                member->anAuthor->text = member->anAuthor->text->next;
                member->anAuthor->text->next = NULL; // initialize

                // read one title and how many times that title has been downloaded
                fscanf(input, " %[^\n]", member->anAuthor->text->textTitle );
                fscanf(input, "%ld",   &(member->anAuthor->text->Download) );
            }
        }
    }

    // recall beginning of linked list
    member = head;

    //for each entry in linked list
    while(NULL != member) // allow for empty list or end of list
    {
        if( NULL != member->anAuthor )
        {
            printf("%s %s %d\n", 
                member->anAuthor->lastName, 
                member->anAuthor->firstName, 
                member->anAuthor->idNumber);

            // for each author/text
            while( NULL != member->anAuthor->text->next )
            {
                printf("%s\n%ld\n", 
                    member->anAuthor->text->textTitle,
                    member->anAuthor->text->Download);

                // step to next author text/title
                member->anAuthor->text = member->anAuthor->text->next;
            }
        }
        // step to next member (I.E next author)
        member = member->next;
    }
}