【问题标题】:How to store the contents of a CSV file in a Linked List?如何将 CSV 文件的内容存储在链接列表中?
【发布时间】:2020-09-15 08:56:07
【问题描述】:

我正在尝试使用 C 将 csv 文件中的内容插入到链接列表中。但是,我得到了很多垃圾输出。源码如下。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct product *customer_head;

struct customer
{
    long long int c_id;//first 6 characters=date & next 6 characters=time & next characters=counter no & city code

    /*Compulsory Fields (Cannot be Skipped)*/
    char name[57];
    long long int ph_no;//10 digit phone number

    /*Non Compulsory Fields (Can be Skipped)*/
    char address[58];
    char city[25];
    char state_code[2];
    char pin[6];
    char email[60];

    struct customer *next;
};
struct customer * load()
{
    FILE * cust=fopen("customer_db.csv","r");
    struct customer *temp,*ptr;
    customer_head=NULL;
    char str[208];
    char *token,*eptr1,*eptr2;
    int line_cnt=0,i=0;

    while(fgets(str,234,cust)!=NULL)
    {
        line_cnt=0;
        i=0;
        ptr=(struct customer *)malloc(sizeof(struct customer));
        for(;str[i];i++)
        {
            if(str[i]=='\n')
            {
                str[i]='\0';
                i=0;
                break;
            }
        }
        token=strtok(str,",");

        while(token!=NULL)
        {

            if(line_cnt==0)
            ptr->c_id=strtoll(token,&eptr1,10);

            else if(line_cnt==1)
            ptr->ph_no=strtoll(token,&eptr2,10);

            else if(line_cnt==2)
            sprintf(ptr->name,"%s",token);

            else if(line_cnt==3)
            sprintf(ptr->address,"%s",token);

            else if(line_cnt==4)
            sprintf(ptr->city,"%s",token);

            else if(line_cnt==5)
            sprintf(ptr->state_code,"%s",token);

            else if(line_cnt==6)
            sprintf(ptr->pin,"%s",token);

            else
            sprintf(ptr->email,"%s",token);

            line_cnt++;

            token=strtok(NULL,",");

        }
        if(customer_head==NULL)
        customer_head=ptr;
        else
        temp->next=ptr;
        temp=ptr;


    }
}
int print(struct customer *h)
{

    while(h->next!=NULL)
    {
        printf("\nCustomer ID: ");
        printf("%lld",h->c_id);
        printf("\nName: ");
        puts(h->name);
        printf("Phone Number: ");
        printf("%lld",h->ph_no);
        printf("\nAddress: ");
        puts(h->address);
        printf("City: ");
        puts(h->city);
        printf("State Code: ");
        puts(h->state_code);
        printf("PIN: ");
        puts(h->pin);
        printf("Email: ");
        puts(h->email);
        h=h->next;
    }
        printf("\nCustomer ID: ");
        printf("%lld",h->c_id);
        printf("\nName: ");
        puts(h->name);
        printf("Phone Number: ");
        printf("%ld",h->ph_no);
        printf("\nAddress: ");
        puts(h->address);
        printf("City: ");
        puts(h->city);
        printf("State Code: ");
        puts(h->state_code);
        printf("PIN: ");
        puts(h->pin);
        printf("Email: ");
        puts(h->email);

    return 1;
}
int main()
{
    load();
    print(customer_head);
}

我还在此处附加了 csv 文件。为了让程序不那么复杂,我从我的 csv 文件中删除了标题。它们是按顺序排列的

客户 ID、电话号码、姓名、地址、城市、州代码、PIN 码、电子邮件

1403201156540201,2226179183,Katherine_Hamilton,87_Thompson_St.,Fremont,IA,502645,k_hamilton@gmail.com
2204201532220103,8023631298,Marc_Knight,-,-,-,-,-
0305201423120305,8025595163,Albie_Rowland,-,Hamburg,NY,140752,-
0607201232220901,4055218053,Grant_Phelps,-,-,-,-,-

破折号 (-) 表示这些字段应保持为空。

输出如下:

Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA502645k_hamilton@gmail.com
PIN: 502645k_hamilton@gmail.com
Email: k_hamilton@gmail.com

Customer ID: 2204201532220103
Name: Marc_Knight
Phone Number: 8023631298
Address: -
City: -
State Code: -
PIN: -
Email: -

Customer ID: 305201423120305
Name: Albie_Rowland
Phone Number: 8025595163
Address: -
City: Hamburg
State Code: NY140752-
PIN: 140752-
Email: -

Customer ID: 607201232220901
Name: Grant_Phelps
Phone Number: 4055218053
Address: -
City: -
State Code: -
PIN: -
Email: -

如您所见,内容在很多地方都被合并了。我不明白为什么。

【问题讨论】:

  • 您的代码缩进不是最理想的。您一直使用sprintf,它不检查边界,也不检查结果。至少使用snprintf。电话号码不是整数,当然也没有签名。您的load 函数的返回值没有意义,而且您也不会返回任何内容,因此这是对您的编译器警告。在继续之前至少解决其中的一些问题。
  • CSV 文件中的空值通常表示为不存在任何值 (Albie_Rowland,,Hamburg)。此外,如果这是用于生产而不是学习,您可能需要使用libcsv
  • 你为什么使用sprintf,例如sprintf(ptr-&gt;address,"%s",token); 而不是 strcpy?? printf("\nCustomer ID: "); --> fputs ("\nCustomer ID: ", stdout); - 不需要转换。 (虽然一个好的编译器会为你进行优化)使用strtok()时不需要str[i]='\0';
  • @Cheatah 我同意,load 函数的返回类型没有意义。我还将sprintf 更改为snprintf,因为它更安全。即使在我进行了这样的更正之后,它仍然给我带来了不可预测的输出。另外我应该为电话号码使用哪种数据类型?
  • struct customer * load() 的返回类型使 Perfect 有意义。它允许您将customer_head 声明为main() 本地并分配load() 的返回值。唯一的问题是 load() 应该在失败时返回 NULL 或在成功时返回最后一个节点 (temp),这是你的头节点,因为你使用 forward-chaining 来填充你的列表. (这就是为什么您的列表将与从文件中读取的数据的顺序相反)

标签: c csv file linked-list fopen


【解决方案1】:

因为从 cmets 你知道你的字符数组的声明受到 one-too-few 字符的影响,至少在 char state_code[2]; 离开你的数组没有 nul 的情况下- 导致未定义行为的终止字符,您应该确保所有输入都具有有效的存储空间。 (不要吝啬缓冲区大小)

一般来说,你让自己变得比实际需要的更难。与其尝试使用strtok() 和计数字段并处理if, else if ... 的8 部分链中的每个字段,不如使用固定的输入字段,因此只需使用sscanf() 解析数据并验证转换次数以确认成功解析,例如

/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
    char buf[MAXC];
    node_t data = { .c_id = 0, .next = NULL };

    while (fgets (buf, MAXC, fp)) { /* read each line in file */
        /* parse and VALIDATE values from line */
        if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
                    &data.c_id, &data.ph_no, data.name, data.address, data.city,
                    data.state_code, data.pin, data.email) == 8) {
            if (!add (list, &data)) /* validate add to list or break */
                break;
        }
    }

    return list;
}

这里,list_t 只是一个附加的“包装器”结构,它为您的链表保存一个 headtail 指针。这允许您在所需范围内声明多个列表,并通过让tail 指针始终指向列表中的最后一个节点(您的temp)来允许相同的 O(1) 插入。在这里,headtail 只是包装器的一部分并作为参数传递,而不必将列表指针声明为全局(不好的做法)。列表中的每个节点和包装器结构都可以写成:

#define BYTE8   8           /* if you need a constant, #define one (or more) */
#define BYTE32 32
#define BYTE64 64
#define MAXC 1024

typedef struct node_t {     /* list node */
    /* 6 characters=date & 6 characters=time & counter no & city code */
    long long int c_id;

    /*Compulsory Fields (Cannot be Skipped)*/
    char name[BYTE64];
    long long int ph_no;    //10 digit phone number

    /*Non Compulsory Fields (Can be Skipped)*/
    char address[BYTE64];
    char city[BYTE32];
    char state_code[BYTE8];
    char pin[BYTE8];
    char email[BYTE64];

    struct node_t *next;
} node_t;

typedef struct {            /* list wrapper with head & tail pointers */
    node_t *head, *tail;
} list_t;

那么,与其编写 load() 来包含 FILE 和列表操作,不如将列表操作分开。只需创建一个add() 函数即可将一个节点添加到您的列表中,例如

/** add node at end of list, update tail to end */
node_t *add (list_t *l, node_t *data)
{
    node_t *node = malloc (sizeof *node);   /* allocate node */
    if (!node) {                            /* validate allocation */
        perror ("malloc-node");
        return NULL;
    }

    *node = *data;                      /* initialize members values */

    if (!l->head)                       /* if 1st node, node is head/tail */
        l->head = l->tail = node;
    else {                              /* otherwise */
        l->tail->next = node;           /* add at end, update tail pointer */
        l->tail = node;
    }

    return node;    /* return new node */
}

现在您的加载函数只需要从文件中读取每一行并在调用add() 之前解析该行,并传递一个指向数据结构的指针以及列表指针作为参数。您的 load() 函数简化为:

/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
    char buf[MAXC];
    node_t data = { .c_id = 0, .next = NULL };

    while (fgets (buf, MAXC, fp)) { /* read each line in file */
        /* parse and VALIDATE values from line */
        if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
                    &data.c_id, &data.ph_no, data.name, data.address, data.city,
                    data.state_code, data.pin, data.email) == 8) {
            if (!add (list, &data)) /* validate add to list or break */
                break;
        }
    }

    return list;
}

(注意: 使用strtok()sscanf() 时,无需从输入字符串中去除尾随'\n' - 只需将其作为strtok() 的分隔符即可或使用sscanf()将其从转换中排除)

此外,您不需要多次调用puts()printf() 来打印列表中每个节点的数据价值。查看您为打印数据而调用了多少函数。您只需拨打一次printf(),例如

/** print all nodes in list */
void prn_list (list_t *l)
{
    if (!l->head) {
        puts ("list-empty");
        return;
    }

    for (node_t *n = l->head; n; n = n->next)
        printf ("\nCustomer ID: %lld\n"
                "Name: %s\n"
                "Phone Number: %lld\n"
                "Address: %s\n"
                "City: %s\n"
                "State Code: %s\n"
                "PIN: %s\n"
                "Email: %s\n", n->c_id, n->name, n->ph_no, n->address, n->city,
                                n->state_code, n->pin, n->email);
}

main() 中,只需声明您的list_t 包装器的一个实例,打开/验证您的FILE,然后将指向列表的指针和文件流传递给您的list_from_csv()(您的load()),然后打印列表,最后释放你分配的所有内存,你就完成了。 (是的,内存将在退出时被释放,但要尽早养成良好的习惯——不久之后你就会在函数中使用分配内存,在return 之前释放失败会导致内存泄漏)

int main (int argc, char **argv) {

    list_t list = { .head = NULL, .tail = NULL };
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    if (!list_from_csv (&list, fp))
        return 1;

    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    prn_list (&list);
    del_list (&list);
}

总而言之,您会得到类似于以下内容的内容:

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

#define BYTE8   8           /* if you need a constant, #define one (or more) */
#define BYTE32 32
#define BYTE64 64
#define MAXC 1024

typedef struct node_t {     /* list node */
    /* 6 characters=date & 6 characters=time & counter no & city code */
    long long int c_id;

    /*Compulsory Fields (Cannot be Skipped)*/
    char name[BYTE64];
    long long int ph_no;    //10 digit phone number

    /*Non Compulsory Fields (Can be Skipped)*/
    char address[BYTE64];
    char city[BYTE32];
    char state_code[BYTE8];
    char pin[BYTE8];
    char email[BYTE64];

    struct node_t *next;
} node_t;

typedef struct {            /* list wrapper with head & tail pointers */
    node_t *head, *tail;
} list_t;


/** add node at end of list, update tail to end */
node_t *add (list_t *l, node_t *data)
{
    node_t *node = malloc (sizeof *node);   /* allocate node */
    if (!node) {                            /* validate allocation */
        perror ("malloc-node");
        return NULL;
    }

    *node = *data;                      /* initialize members values */

    if (!l->head)                       /* if 1st node, node is head/tail */
        l->head = l->tail = node;
    else {                              /* otherwise */
        l->tail->next = node;           /* add at end, update tail pointer */
        l->tail = node;
    }

    return node;    /* return new node */
}

/** print all nodes in list */
void prn_list (list_t *l)
{
    if (!l->head) {
        puts ("list-empty");
        return;
    }

    for (node_t *n = l->head; n; n = n->next)
        printf ("\nCustomer ID: %lld\n"
                "Name: %s\n"
                "Phone Number: %lld\n"
                "Address: %s\n"
                "City: %s\n"
                "State Code: %s\n"
                "PIN: %s\n"
                "Email: %s\n", n->c_id, n->name, n->ph_no, n->address, n->city,
                                n->state_code, n->pin, n->email);
}

/** delete all nodes in list */
void del_list (list_t *l)
{
    node_t *n = l->head;

    while (n) {
        node_t *victim = n;
        n = n->next;
        free (victim);
    }
}

/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
    char buf[MAXC];
    node_t data = { .c_id = 0, .next = NULL };

    while (fgets (buf, MAXC, fp)) { /* read each line in file */
        /* parse and VALIDATE values from line */
        if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
                    &data.c_id, &data.ph_no, data.name, data.address, data.city,
                    data.state_code, data.pin, data.email) == 8) {
            if (!add (list, &data)) /* validate add to list or break */
                break;
        }
    }

    return list;
}

int main (int argc, char **argv) {

    list_t list = { .head = NULL, .tail = NULL };
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    if (!list_from_csv (&list, fp))
        return 1;

    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    prn_list (&list);
    del_list (&list);
}

使用/输出示例

使用dat/customer_list.txt 中的输入文件,运行您将收到的程序:

$ ./bin/customer_list dat/customer_list.txt

Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA
PIN: 502645
Email: k_hamilton@gmail.com

Customer ID: 2204201532220103
Name: Marc_Knight
Phone Number: 8023631298
Address: -
City: -
State Code: -
PIN: -
Email: -

Customer ID: 305201423120305
Name: Albie_Rowland
Phone Number: 8025595163
Address: -
City: Hamburg
State Code: NY
PIN: 140752
Email: -

Customer ID: 607201232220901
Name: Grant_Phelps
Phone Number: 4055218053
Address: -
City: -
State Code: -
PIN: -
Email: -

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有 2 个职责:(1)始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放

您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出已分配块的边界,尝试读取或基于未初始化的值进行条件跳转,最后,以确认您释放了已分配的所有内存。

对于 Linux,valgrind 是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。

$ valgrind ./bin/customer_list dat/customer_list.txt
==14823== Memcheck, a memory error detector
==14823== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14823== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==14823== Command: ./bin/customer_list dat/customer_list.txt
==14823==

Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA
PIN: 502645
Email: k_hamilton@gmail.com

<snipped rest>

==14823==
==14823== HEAP SUMMARY:
==14823==     in use at exit: 0 bytes in 0 blocks
==14823==   total heap usage: 7 allocs, 7 frees, 6,728 bytes allocated
==14823==
==14823== All heap blocks were freed -- no leaks are possible
==14823==
==14823== For counts of detected and suppressed errors, rerun with: -v
==14823== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放已分配的所有内存并且没有内存错误。

虽然您可以通过确保每个字符串有足够的存储空间来解决大部分问题,但请花时间考虑使用sscanf() 处理值的解析,并且由于您控制了转换,因此没有必要从从文件读取的行中删除尾随 '\n'。 (只是不要在从输入字符串解析的值中包含换行符)如果您确实想从末尾解析 '\n',您应该使用,例如

    str[strcspn (str, "\n")] = 0;

最后,与sscanf()strcspn() 一起使用的格式字符串,请确保您完全了解它们的工作原理,请参阅man 3 scanfman 3 strspn

如果您还有其他问题,请告诉我。

【讨论】:

  • 这是一个很有帮助的解释。我可以理解我的一些错误。非常感谢!
  • 这是一个很有帮助的解释。我可以理解我的一些错误。非常感谢!你能解释一下为什么你选择将这些声明为全局变量而不是分配单独的大小吗? #define BYTE8 8 #define BYTE32 32 #define BYTE64 64 #define MAXC 1024
  • 当然。每当您需要一个常量时,您应该将它们 #define 放在顶部(或使用全局 enum 来做同样的事情)。这样,如果您以后需要调整一个常量,您就不必在代码主体中寻找必须调整的每个声明或循环变量。这样评论就说/* if you need a constant, #define one (or more) */。祝你编码好运! :)
【解决方案2】:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum operations {EXIT, ADD_BOOK, ISSUE_BOOK, RETURN_BOOK, DISPLAY_BOOKS,
                SORT_BOOKS, DISPLAY_BOOK_SUBJECTWISE};
typedef enum operations MENU;
typedef struct book
{
    int bookId;
    char bookName[30];
    char subject[30];
    char author[30];
    float price;
}BOOK;
typedef struct node
{
    struct node *prev;
    BOOK info;
    struct node *next;
}NODE;
NODE *head=NULL;
NODE *issuehead=NULL;
static int counter=0;
MENU menu_function()
{
    int choice;
    printf(" 1. Add Book\n");
    printf(" 2. Issue Book\n");
    printf(" 3. Return Book\n");
    printf(" 4. Display Book\n");
    printf(" 5. Sort Book\n");
    printf(" 6. Display Books Subject-wise\n");
    printf(" 0. EXIT\n");
    printf(" Enter your choice::");
    scanf("%d",&choice);
    if(choice < 0 || choice > 6)
    {
        printf(" Error: Enter valid choice\n");
    }
    return choice;
}
void FreeList()
{
    while(CountNodes(head))
    {
        DeleteBook();
    }
    while(CountNodes(issuehead))
    {
        DeleteIssues();
    }
}
int CountNodes(NODE *trav)
{
    int count=0;
    while(trav!=NULL)
    {
        count++;
        trav=trav->next;
    }
    return count;
}
void DeleteBook()
{
    NODE *temp=head;
    head = head->next;
    free(temp);
    temp=NULL;
}
void DeleteIssues()
{
    NODE *temp=issuehead;
    issuehead = issuehead->next;
    free(temp);
    temp=NULL;
}
void AcceptData(BOOK *book)
{
    book->bookId=++counter;
    getchar();
    printf(" Enter Book name::");
    scanf("%[^\n]s",&book->bookName);
    getchar();
    printf(" Enter Subject::");
    scanf("%[^\n]s",&book->subject);
    getchar();
    printf(" Enter author::");
    scanf("%[^\n]s",&book->author);
    printf(" Enter price::");
    scanf("%f",&book->price);
}
void DisplayData(BOOK book)
{
    printf(" %d\t\t",book.bookId);
    printf(" %s\t\t",book.bookName);
    printf(" %s\t\t",book.subject);
    printf(" %s\t\t",book.author);
    printf(" %g\n",book.price);
}
NODE *CreateNode()
{
    NODE *temp;
    temp = (NODE *) malloc(sizeof(NODE));
    temp->next=NULL;
    temp->prev=NULL;
    return temp;
}
void AddtoBooklist(BOOK book)
{
    NODE *new_node;
    new_node=CreateNode();
    new_node->info=book;
    if(head == NULL)
    {
        head=new_node;
    }
    else
    {
        new_node->next=head;
        head->prev=new_node;
        head=new_node;
    }
}
void DisplayBooks(NODE *trav)
{
    if(trav==NULL)
    {
        printf(" Book list is empty...\n");
    }
    else
    {
        printf(" Available Books\n");
        while(trav!=NULL)
        {
            DisplayData(trav->info);
            trav=trav->next;
        }
        printf("\n");
    }
}
void IssueBook()
{
    NODE *trav=head, *prev=NULL;
    NODE *temp, *right;
    int bookId;
    printf(" Enter Book ID::");
    scanf("%d",&bookId);
    while(bookId != trav->info.bookId)
    {
        prev=trav;
        trav=trav->next;
        if(trav==NULL)
        {
            printf(" Book not found...\n");
            break;
        }
    }
    if(trav==head)
    {
        temp = trav;
        head->prev=NULL;
        head = head->next;
        trav=NULL;
        IssueAtFirst(temp);
        printf(" Book issued successfully...\n");
    }
    else if(trav->next==NULL)
    {
        temp=trav;
        prev->next=NULL;
        trav->prev=NULL;
        trav=NULL;
        IssueAtFirst(temp);
        printf(" Book issued successfully...\n");
    }
    else
    {
        temp=trav;
        right=trav->next;
        prev->next=right;
        right->prev=prev;
        trav->next=NULL;
        trav->prev=NULL;
        trav=NULL;
        IssueAtFirst(temp);
        printf(" Book issued successfully...\n");
    }
}
void IssueAtFirst(NODE *temp)
{
    if(issuehead == NULL)
    {
        issuehead=temp;
        temp->next=NULL;
        temp->prev=NULL;
        temp=NULL;
    }
    else
    {
        temp->next=issuehead;
        temp->prev=NULL;
        issuehead=temp;
        temp=NULL;
    }
}
void ReturnBook()
{
    NODE *trav=issuehead, *prev=NULL;
    NODE *temp, *right;
    int bookId;
    printf(" Enter Book ID::");
    scanf("%d",&bookId);
    while(bookId != trav->info.bookId)
    {
        prev=trav;
        trav=trav->next;
        if(trav==NULL)
        {
            printf(" Book not found...\n");
            break;
        }
    }
    if(trav==issuehead)
    {
        temp = trav;
        issuehead->prev = NULL;
        issuehead = issuehead->next;
        trav=NULL;
        ReturnAtFirst(temp);
        printf(" Book returned successfully...\n");
    }
    else if(trav->next==NULL)
    {
        temp=trav;
        prev->next=NULL;
        trav->prev=NULL;
        trav=NULL;
        ReturnAtFirst(temp);
        printf(" Book returned successfully...\n");
    }
    else
    {
        temp=trav;
        right=trav->next;
        prev->next=right;
        right->prev=prev;
        trav->next=NULL;
        trav->prev=NULL;
        trav=NULL;
        ReturnAtFirst(temp);
        printf(" Book returned successfully...\n");
    }
}
void ReturnAtFirst(NODE *temp)
{
    if(head == NULL)
    {
        head=temp;
        temp->next=NULL;
        temp->prev=NULL;
        temp=NULL;
    }
    else
    {
        head->prev=temp;
        temp->next=head;
        temp->prev=NULL;
        head=temp;
        temp=NULL;
    }
}
void SortBooks()
{
    NODE *trav=head,*right=head->next;
    BOOK temp;
    while(trav->next!=NULL)
    {
        right=trav->next;
        while(right!=NULL)
        {
            if(trav->info.bookId > right->info.bookId)
            {
                temp = trav->info;
                trav->info = right->info;
                right->info = temp;
            }
            right=right->next;
        }
        trav=trav->next;
    }
}
void AddBooksToFile()
{
    NODE *trav=head;
    FILE *fp;
    fp=fopen("Booklist.dat","wb");
    if(fp!=NULL)
    {
        while(trav!=NULL)
        {
            fwrite(&trav->info, sizeof(BOOK),1,fp);
            trav=trav->next;
        }
    }
    fclose(fp);
}
void AddIssuesToFile()
{
    NODE *trav=issuehead;
    FILE *fp=issuehead;
    fp=fopen("Issuelist.dat","wb");
    if(fp!=NULL)
    {
        while(trav!=NULL)
        {
            fwrite(&trav->info, sizeof(BOOK),1,fp);
            trav=trav->next;
        }
    }
    fclose(fp);
}
void ReadIssuesFromFile()
{
    BOOK book;
    FILE *fp;
    fp=fopen("Issuelist.dat","rb");
    if(fp!=NULL)
    {
        while((fread(&book,sizeof(BOOK),1,fp))!=0)
        {
            AddtoIssuelist(book);
        }
    }
    fclose(fp);
}
void ReadBooksFromFile()
{
    BOOK book;
    FILE *fp;
    fp=fopen("Booklist.dat","rb");
    if(fp!=NULL)
    {
        while((fread(&book,sizeof(BOOK),1,fp))!=0)
        {
            AddtoBooklist(book);
        }
    }
    fclose(fp);
}
void AddtoIssuelist(BOOK book)
{
    NODE *new_node;
    new_node=CreateNode();
    new_node->info=book;
    if(issuehead == NULL)
    {
        issuehead=new_node;
    }
    else
    {
        new_node->next=issuehead;
        issuehead->prev=new_node;
        issuehead=new_node;
    }
}
void DisplaySubjectWise(NODE *head)
{
    NODE *trav=head;
    char subject[30];
    printf(" Enter subject::");
    scanf("%s",&subject);
    while(trav!=NULL)
    {
        if(stricmp(subject, trav->info.subject)== 0)
        {
            DisplayData(trav->info);
        }
        trav=trav->next;
    }
}
int main()
{
    MENU choice;
    int data;
    BOOK book;
    ReadBooksFromFile();
    ReadIssuesFromFile();
    while((choice=menu_function())!=EXIT)
    {
        switch(choice)
        {
        case ADD_BOOK:
            AcceptData(&book);
            AddtoBooklist(book);
            printf(" Book added to library successfully...\n");
            break;
        case ISSUE_BOOK:
            if(head==NULL)
            {
                printf(" No Books are available now...\n");
                break;
            }
            else
            {
                IssueBook();
            }
            break;
        case RETURN_BOOK:
            if(issuehead==NULL)
            {
                printf(" No Books are issued...\n");
                break;
            }
            else
            {
                ReturnBook();
            }
            break;
        case DISPLAY_BOOKS:
            DisplayBooks(head);
            DisplayBooks(issuehead);
            printf("\n");
            break;
        case SORT_BOOKS:
            if(head==NULL)
            {
                printf(" No Books to sort...\n");
                break;
            }
            SortBooks();
            break;
        case DISPLAY_BOOK_SUBJECTWISE:
            if(head==NULL)
            {
                printf(" No Books to display...\n");
                break;
            }
            DisplaySubjectWise(head);
            break;
        }
    }
    AddBooksToFile();
    AddIssuesToFile();
    FreeList();
    return 0;
}

供参考

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 1970-01-01
    • 2018-04-22
    • 2013-01-27
    • 2019-10-20
    • 2016-02-23
    相关资源
    最近更新 更多