0

我试图从文本文件中读取链接列表。文本文件的书名、作者和年份用“:”分隔。每本书都在一个单独的行上。文本文件条目如下所示:

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

4 回答 4

5

您的代码现在存在多个问题。

第一个(我不骗你)是代码格式和缩进。您粘贴的示例没有常规格式或缩进可言。即使在这样的简短示例中,也更难以遵循代码流。始终缩进您的代码,并选择一种编码风格(有几种)并坚持下去。

关于代码流,第一个问题是错误检查。即,您检查fopen返回状态,但在打开文件失败时未采取足够的措施。

第二个问题是概念问题。您似乎没有意识到 N 个字符的数组只能容纳长度为 N-1 的字符串。因此,char[4]几乎不是将年份存储为字符串的合适格式。

现在已经处理了这些问题,以下是在任何情况下都会阻止您的代码工作的实际缺陷:

1) 该fgets函数将向上读取,直到它填满您的缓冲区或到达行尾或文件结尾字符。然而,您仍然调用fgets三次以尝试读取文件中的单行条目。你想做的事情不太可能。您必须重新考虑循环的内容。

2)您的“主”循环条件可能存在缺陷。feof这是对& co的使用非常普遍的误解。假设您的数据文件最后包含一个换行符(并且这样做只是常规的),您的循环将执行一次太多。

最好像这样构造你的行阅读循环:

while (fgets(buffer, BUF_SIZE, stdin)) { /* parse buffer */ }

3)您的代码中的内存管理存在基本问题:即该函数addEntry无法分配内存来存储您的记录。相反,您的链表中的所有条目最终都将指向您在main函数中分配的同一个共享缓冲区。

有几种方法可以解决这个问题。malloc一种是对结构的每个成员BookNodetitle、、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并从那里构建,而不是再次重写?

于 2012-06-03T13:53:43.340 回答
0

addEntry应该为标题、作者和年份分配内存。
此外,执行fgets3 次将读取 3 行。您需要fgets每个循环一个,并将结果拆分为不同的部分(例如使用strtok_r)。

您所做的是保存指向静态缓冲区的指针。读取下一行时,此缓冲区将被新数据覆盖。

请注意,如果您分配了数据,您最终必须释放它。条目的析构函数需要释放。

于 2012-06-03T12:50:42.467 回答
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);
    }
}
于 2012-06-03T16:21:33.097 回答
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"
于 2012-06-03T16:54:51.147 回答