我正在尝试从C中的文本文件中读取CSV.文本文件格式为
1,Bob,bob@gmail.com
2,Daniel,daniel@gmail.com
3,John,john@gmail.com
Run Code Online (Sandbox Code Playgroud)
当我运行程序时,数字显示正常,但名称和电子邮件显示为垃圾.这是我的计划......
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int number;
char* name;
char* email;
} Owner;
Owner owners[100];
int load(char* filename)
{
char buffer[200];
char token[50];
Owner* owner;
int owners_size = 0;
FILE* file = fopen(filename, "r");
while(fgets(buffer, 200, file) != NULL)
{
owner = (Owner*)malloc(sizeof(Owner));
owner->number = atoi(strtok(buffer, ","));
owner->name = strtok(NULL, ",");
owner->email = strtok(NULL, ",");
owners[owners_size++] = *owner;
}
fclose(file);
return owners_size;
}
int main()
{
int choise, owners_size, index;
char* owners_filename = "owners2.txt";
owners_size = load(owners_filename);
if(owners_size)
{
printf("owners size: %d\n\n", owners_size);
for(index = 0; index < owners_size; index++)
printf("%d, %s %s\n", owners[index].number, owners[index].name, owners[index].email);
}
}
Run Code Online (Sandbox Code Playgroud)
谁能告诉我原因是什么.我感谢您的帮助.
两个问题:
您没有为结构中的字符串分配空间:
typedef struct
{
int number;
char *name;
char *email;
} Owner;
Run Code Online (Sandbox Code Playgroud)
您需要为指向这些指针的指针提供空间来保存名称.
您继续提供指向缓冲区的指针,该指针将重复用于每行输入:
while(fgets(buffer, 200, file) != NULL)
{
owner = (Owner*)malloc(sizeof(Owner));
owner->number = atoi(strtok(buffer, ","));
owner->name = strtok(NULL, ",");
owner->email = strtok(NULL, ",");
owners[owners_size++] = *owner;
}
Run Code Online (Sandbox Code Playgroud)
第一行存储为缓冲区中的一些指针.然后下一行覆盖缓冲区并再次切断该行,遍历原始输入.
考虑使用strdup():
while (fgets(buffer, 200, file) != NULL)
{
owner = (Owner *)malloc(sizeof(Owner));
owner->number = atoi(strtok(buffer, ","));
owner->name = strdup(strtok(NULL, ","));
owner->email = strdup(strtok(NULL, ","));
owners[owners_size++] = *owner;
}
Run Code Online (Sandbox Code Playgroud)
这是稍微有点危险的代码(我不会在生产代码中使用它)因为它没有检查strtok()在预期时找到了一个令牌(或者strdup()是成功的).再说一遍,我也不会strtok()在生产代码中使用; 我会使用POSIX strtok_r()或Microsoft的,strtok_s()如果它们可用,或者一些替代技术,可能使用strspn()和strcspn().如果strdup()没有,您可以使用相同或不同的名称编写自己的名称:
char *strdup(const char *str)
{
size_t len = strlen(str) + 1;
char *dup = malloc(len);
if (dup != 0)
memmove(dup, str, len); // Or memcpy() - that is safe in this context
return(dup);
}
Run Code Online (Sandbox Code Playgroud)
您可能会注意到您的代码仅适用于简单的CSV文件.如果您遇到这样的行(这是合法的CSV),您就会遇到问题(您的值中带引号,并且由于引用字符串中的逗号而导致错误分裂):
1,"Bob ""The King"" King","Bob King, Itinerant Programmer <bob@gmail.com>"
Run Code Online (Sandbox Code Playgroud)