我试图从文本文件中读取链接列表。文本文件具有书籍,作者和年份的标题,以“:”分隔。每本书都在一个单独的行上。文本文件条目如下所示:
Absalom, Absalom!:William Faulkner:1936
After Many a Summer Dies the Swan:Aldous Huxley:1939
Ah, Wilderness!:Eugene O'Neill:1933
我正在从头开始重写它。评论将不胜感激。
#include <stdlib.h>
#include <stdio.h>
struct BookNode
{
char linebuffer[128];
char delim[]=":";
char * Title[50];
char * Author[50];
char * Year[5];
struct BookNode *next;
// char *token = NULL;
};
int main(void)
{
static const char booklist[]= "booklist.txt";
FILE *fr=fopen("booklist.txt", "r");
if ( fr != NULL)
{
char Title[50];
char Author[50];
char Year[5]
struct BookNode Booknode;
while (fgets(linebuffer,128, fr) != NULL &&
sscanf(line, "%49s %49s %4s",
&BookNode.Title, BookNode.Author, BookNode.Year)==3)
{
printf("%50s %50s %5s",
BookNode.Title, BookNode.Author, BookNode.Year);
}
}
答案 0 :(得分:5)
您的代码目前存在多个问题。
第一个(我不是你的孩子)是代码格式和缩进。您粘贴的样本没有常规格式或缩进。即使在诸如此类的短样本中,遵循代码流也更加困难。总是缩进你的代码,并选择一种编码风格(有几种)并坚持下去。
关于代码流,第一个问题是错误检查。即,您检查fopen
返回状态,但如果打开文件失败,则不采取足够的措施。
第二个问题是概念问题。您似乎没有意识到N个字符的数组只能容纳长度为N-1的字符串。因此,char[4]
几乎不是用于将年份存储为字符串的合适格式。
现在已经解决了这些问题,以下是阻止您的代码在任何情况下工作的实际缺陷:
1)fgets
函数将读取,直到它填充缓冲区或到达行尾或文件结束字符。然而,您仍然会调用fgets
三次尝试读取文件中的单行条目。你不想做什么。你必须重新考虑你的循环内容。
2)您的“主要”循环条件可能存在缺陷。这是对feof
&amp;的使用的一个非常普遍的误解。合。假设你的数据文件最后包含一个换行符(并且它只是常规的),你的循环将执行一次太多。
最好像这样构建你的行读取循环:
while (fgets(buffer, BUF_SIZE, stdin)) { /* parse buffer */ }
3)您的代码中存在内存管理的基本问题:即,函数addEntry
无法分配内存来存储您的记录。相反,链接列表中的所有条目最终都将指向您在main
函数中分配的相同共享缓冲区。
有几种方法可以解决这个问题。一种方法是对malloc
结构的每个成员(BookNode
,title
和author
)使用多次调用year
。另一种可能更好的方法是使用可变大小的结构,如下所示:
struct BookNode {
char *title;
char *author;
char *year;
struct BookNode *next;
char buffer[]; // this shorthand requires C99
};
对于每个struct BookNode
,您可以在它们之后分配足够的存储空间,以便您可以在那里复制共享缓冲区的内容。 title
,author
和year
然后指向此附加存储。这样,您不会在循环的下一次迭代中覆盖其他BookNode的内容。而且您只需要一个free
来释放整个节点。
我可能没有列出代码中的所有问题。或许不是另一次重写,你应该首先尝试解决一个较小的子问题,例如从stdin
读取一个条目并从那里开始构建?
答案 1 :(得分:0)
addEntry
应为标题,作者和年份分配内存
此外,执行fgets
三次将读取3行。每个循环需要一个fgets
,并将结果拆分为不同的部分(例如,使用strtok_r
)。
您要做的是保存指向静态缓冲区的指针。读取下一行时,将使用新数据覆盖此缓冲区。
请注意,如果您分配了数据,则必须最终释放它。条目的析构函数需要释放。
答案 2 :(得分:0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct BookNode {
char * Title;
char * Author;
char * Year;
struct BookNode * next;
} * head;
void addEntry(char * T, char * A, char * Y);
void display();
int numEntries();
//void writeBookData(struct BookNode * selection);
void free_book(struct BookNode *bnp){
if(bnp == NULL) return;
free(bnp->Title);
free(bnp->Author);
free(bnp->Year);
free_book(bnp->next);
free(bnp);
}
int main() {
FILE * fpointer;
fpointer=fopen("booklist.txt","r");
if(fpointer == NULL){
printf("Booklist could not be opened.\n");
exit(EXIT_FAILURE);
}
char Title[50+1];
char Author[50+1];
char Year[4+1];
head = NULL;
while (EOF!=fscanf(fpointer, "%50[^:]%*c%50[^:]%*c%4[^\n]%*c", Title, Author, Year)){
//note:The input number of characters is limited (Eg50), it (because minutes in excess of the limit is used in the following items) there must be large enough.
addEntry(Title, Author, Year);
}
fclose(fpointer);
int entryCount = numEntries();
printf("There are %d entries in this Book list\n", entryCount);
display();
free_book(head);
return 0;
}
void addEntry(char * T, char * A, char * Y){
struct BookNode * tempNode, * iterator;
tempNode = (struct BookNode *)malloc(sizeof(struct BookNode));
tempNode->Title = (char *)malloc(strlen(T)+1);
strcpy(tempNode->Title, T);
tempNode->Author = (char *)malloc(strlen(A)+1);
strcpy(tempNode->Author, A);
tempNode->Year = (char *)malloc(strlen(Y)+1);
strcpy(tempNode->Year, Y);
tempNode->next = NULL;
iterator = head;
if (head == NULL){
head = tempNode;
} else {
while(iterator->next != NULL){
iterator = iterator->next;
}
iterator->next = tempNode;
}
}
int numEntries(){
if(head == NULL)
return 0;
else{
int count;
struct BookNode *iterator;
for(count=0, iterator=head; iterator!=NULL; iterator = iterator->next, ++count)
;
return count;
}
}
void display(){
if(head == NULL)
return ;
else{
struct BookNode *iterator;
for(iterator=head; iterator!=NULL; iterator = iterator->next)
fprintf(stdout, "%s:%s:%s\n", iterator->Title, iterator->Author, iterator->Year);
}
}
答案 3 :(得分:0)
strtok的例子
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char line[] = "Absalom, Absalom!:William Faulkner:1936\n";
char *p;
char * Title;
char * Author;
char * Year;
p = strtok(line, ":");
Title = strdup(p);
Author = strdup(strtok(NULL, ":"));
Year = strdup(strtok(NULL, ": \n"));
printf("\"%s\",\"%s\",\"%s\"\n", Title, Author, Year);
free(Title);
free(Author);
free(Year);
}
//result:"Absalom, Absalom!","William Faulkner","1936"