【发布时间】: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->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