如何将 CSV 文件的内容存储在链表中?
How to store the contents of a CSV file in a Linked List?
我正在尝试使用 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]='[=10=]';
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 文件中删除了标题。他们的顺序是
Customer_ID,Phone_Number,姓名,地址,城市,State_Code,密码,电子邮箱
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: -
如您所见,很多地方的内容正在合并。我不明白为什么。
因为从评论中你知道你的字符数组声明受到 one-too-few 字符的影响,至少在 char state_code[2];
离开你的情况下没有 nul-terminating 字符导致 Undefined Behavior 的数组,你应该确保你有所有输入的有效存储。 (不要吝啬缓冲区大小)
总的来说,你让自己的事情变得比需要的更难了。与其尝试使用 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
只是一个附加的 "wrapper" 结构,它包含一个 head
和 tail
指针用于您的链表。这允许您在所需范围内声明多个列表,并通过使 tail
指针始终指向列表中的最后一个节点(您的 temp
)来允许相同的 O(1) 插入。在这里,head
和 tail
只是包装器的一部分并作为参数传递,而不是必须将列表指针声明为全局(不良做法)。列表中的每个节点和包装器结构都可以写成:
#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
包装器的实例,open/validate 您的 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);
}
示例Use/Output
在 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: -
内存Use/Error检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址 因此,(2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入 beyond/outside 您分配的块的边界,尝试读取或基于未初始化的条件跳转值,最后,确认您释放了所有已分配的内存。
对于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 scanf and man 3 strspn
如果您还有其他问题,请告诉我。
#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;
}
供大家参考
我正在尝试使用 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]='[=10=]';
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 文件中删除了标题。他们的顺序是
Customer_ID,Phone_Number,姓名,地址,城市,State_Code,密码,电子邮箱
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: -
如您所见,很多地方的内容正在合并。我不明白为什么。
因为从评论中你知道你的字符数组声明受到 one-too-few 字符的影响,至少在 char state_code[2];
离开你的情况下没有 nul-terminating 字符导致 Undefined Behavior 的数组,你应该确保你有所有输入的有效存储。 (不要吝啬缓冲区大小)
总的来说,你让自己的事情变得比需要的更难了。与其尝试使用 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
只是一个附加的 "wrapper" 结构,它包含一个 head
和 tail
指针用于您的链表。这允许您在所需范围内声明多个列表,并通过使 tail
指针始终指向列表中的最后一个节点(您的 temp
)来允许相同的 O(1) 插入。在这里,head
和 tail
只是包装器的一部分并作为参数传递,而不是必须将列表指针声明为全局(不良做法)。列表中的每个节点和包装器结构都可以写成:
#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
包装器的实例,open/validate 您的 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);
}
示例Use/Output
在 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: -
内存Use/Error检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址 因此,(2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入 beyond/outside 您分配的块的边界,尝试读取或基于未初始化的条件跳转值,最后,确认您释放了所有已分配的内存。
对于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 scanf and man 3 strspn
如果您还有其他问题,请告诉我。
#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;
}
供大家参考