事情是这样的。我有一个程序,它将不同的作者存储在一个链表中,每个作者都有自己的记录,每个记录保存他的文本,组织在一个链表中。从文件中读取数据。下面是代码:
#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 %dn", member->anAuthor->lastName, member->anAuthor->firstName, member->anAuthor->idNumber);
for (j = 0; j < member->anAuthor->textNum; j++)
{
printf("%sn", member->anAuthor->text->textTitle);
printf("%ldn", member->anAuthor->text->Download);
member->anAuthor->text = member->anAuthor->text->next;
}
member = member->next;
}
}
}
我已经通过gdb运行了这个程序,一切都很好。然而,当我到达这条线printf("%sn", member->anAuthor->text->textTitle);
时,我得到了一个段故障。显然member->anAuthor->text
字段是空的,它的地址是0x0。member
和member->anAuthor
上的数据和内存地址正确
怎么了?
当您读取每个作者的文本时,您使用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
初始化之后,即。)
也就是说,你的代码中有各种各样的"气味":
- 这些结构的名字很可怕。我知道这是一个任务,你的结构作为起点,但为什么文本节点被称为
AuthorRecord
,当他们明显不同于AutorType
? - 如前所述,为结构体定义指针类型不会增加任何东西;它只会混淆,特别是如果类型命名为
AuthorRecordType
,而不是AuthorPtr
或PAuthor
。在C语言中,星号表示指针类型;很难找到比这更有表现力的了。(另外,它更容易输入) 跟踪带有额外成员的列表中的条目数可能是有用的,但列表的遍历应该始终使用列表结构本身(即 - 当您向列表中添加元素时,在需要内存时调用
malloc
,而不是提前调用。如果在读取第一个元素之前malloc它,然后将其设置为NULL
,因为事实证明您根本不需要它,那么您将创建内存泄漏。 - 每个
malloc
在你完成后都需要一个free
。(我知道你的代码目前还不完整;只是说)。 - 你的整个
scanf
序列需要错误检查。如果输入不正确,很容易陷入无限循环。(旁注:在这里发布一个简短的示例输入片段也很有帮助,以帮助我们找到错误。) - 考虑编写小函数来创建每个类型,清理它们并将它们添加到列表中;不要把所有东西都放进
main
。将读取与创建结构分开也是一个好主意。 - 使用像这样的成员引用长序列:
member->anAuthor->text->next
。考虑使用临时指针。这将使引用更短(text->next
),也希望代码更干净。
next
指针),以避免可能的不一致。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 %dn",
member->anAuthor->lastName,
member->anAuthor->firstName,
member->anAuthor->idNumber);
// for each author/text
while( NULL != member->anAuthor->text->next )
{
printf("%sn%ldn",
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;
}
}