提问人:Mr Cake 提问时间:5/14/2023 最后编辑:ArctodusMr Cake 更新时间:5/14/2023 访问量:64
我正在尝试制作一个程序,该程序从csv文件中获取数据/值并打印出来。但我在某些方面很挣扎
I am trying to make a program that takes data/values from a csv file and print it. But I am struggling with some parts
问:
我正在尝试制作一个读取csv文件的程序,如下所示:
name,hp,damage
duck,20,5
cat,30,10
giraffe,100,20
我想像这样打印上面的csv文件:
name:duck hp:20 damage:5
name:cat hp:30 damage:10
name:giraffe hp:100 damage:20
要求是 csv 文件的标头部分(name、hp、damage)应存储到名为“header”的数组中,并且在打印 csv 文件时必须使用数组“header”。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[1000];
int hp;
int damage;
} Monster;
typedef struct {
char header1[4];
char header2[2];
char header3[6];
} Header;
int main()
{
FILE* fp = fopen("entityData.csv", "r");
if (!fp) {
printf("Error opening file\n");
return 1;
}
Monster monsters[100];
int num_records = 0;
char line[100];
Header headerList[20];
fgets(headerList, sizeof(headerList), fp);
char *hd1, *hd2, *hd3;
hd1 = strtok(headerList, ",");
strncpy(monsters[num_records].name, hd1, 20);
hd2 = strtok(NULL, ",");
hd3 = strtok(NULL, "\n");
while (fgets(line, sizeof(line), fp))
{
char* token = strtok(line, ",");
strncpy(monsters[num_records].name, token, 20);
token = strtok(NULL, ",");
monsters[num_records].hp = atoi(token);
token = strtok(NULL, ",");
monsters[num_records].damage = atoi(token);
num_records++;
}
for (int i = 0; i < num_records; i++) {
printf("name:%s hp:%d damage:%d\n",
monsters[i].name, monsters[i].hp, monsters[i].damage);
}
fclose(fp);
return 0;
}
这是我到目前为止的代码。我相信我能够将每个标头值放入 hd1、hd2 和 hd3 中,但我不确定如何将它们放入数组中并在以后使用。我也知道打印部分现在是错误的,但我这样写只是为了测试每个标题的值是否打印良好。
此外,原始 csv 文件是韩文的,但为了简单起见,我将它们翻译成了英文。因此,数组大小可能与我试图实现的目标不匹配。
任何帮助将不胜感激!
答:
1赞
Allan Wind
5/14/2023
#1
您假设标题顺序是固定的,因此这些要求对我来说意义不大(而不是读取标题,然后使用该信息将列号映射到结构成员)。
使用符号常量而不是魔术值。当你这样做时,很明显,> .
NAME_LEN
LINE_LEN
(部分修复)不要读取超过记录,以防止缓冲区溢出。我没有,但如果数组中的数据多于空间,则可能希望生成警告。
MONSTERS
添加了错误处理。每一行都是一个自然的同步点,因此很容易跳过无效的行。
strtok()
由于标头和数据线的解析方式相同,只是使用方式不同。这也修复了第 3 个期望 a 但数据线 a 的缺陷。
strtok()
'\n'
','
(不固定)请考虑使用 而不是 ,以便检测错误。 出错时返回 0。
strtol()
atoi()
atoi()
#define _POSIX_C_SOURCE 200809L // strdup()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_LEN 100
#define MONSTERS 100
#define NAME_LEN 1000
#define VALUES 3
typedef struct {
char name[NAME_LEN];
int hp;
int damage;
} Monster;
int main(void) {
FILE* fp = fopen("entityData.csv", "r");
if (!fp) {
printf("Error opening file\n");
return 1;
}
char *header[VALUES] = { 0 };
Monster monsters[MONSTERS];
int num_records = -1;
for(; num_records < MONSTERS; num_records++) {
char line[LINE_LEN];
if(!fgets(line, sizeof(line), fp))
break;
char *name = strtok(line, ",");
char *hp = strtok(NULL, ",");
char *damage = strtok(NULL, "\n");
if(!name || !hp || !damage) {
fprintf(stderr, "strtok failed at \"%s\"\n", line);
num_records--;
continue;
}
// header
if(num_records == -1) {
header[0] = strdup(name);
header[1] = strdup(hp);
header[2] = strdup(damage);
if(!header[0] || !header[1] || !header[2]) {
fprintf(stderr, "strdup failed\n");
return 1;
}
continue;
}
// data
strncpy(monsters[num_records].name, name, NAME_LEN);
if(LINE_LEN >= NAME_LEN)
monsters[num_records].name[NAME_LEN - 1] = '\0';
monsters[num_records].hp = atoi(hp);
monsters[num_records].damage = atoi(damage);
}
for (int i = 0; i < num_records; i++) {
printf("%s:%s %s:%d %s:%d\n",
header[0],
monsters[i].name,
header[1],
monsters[i].hp,
header[2],
monsters[i].damage);
}
fclose(fp);
for(int i = 0; i < VALUES; i++)
free(header[i]);
}
和示例会话:
name:duck hp:20 damage:5
name:cat hp:30 damage:10
name:giraffe hp:100 damage:20
评论
0赞
Mr Cake
5/14/2023
嗨,我注意到 strdup() 不适用于 C 语言,即使包含第一个 #define。有没有办法不使用 strdup()?
0赞
Harith
5/14/2023
@Mr蛋糕 它怎么不起作用?
0赞
Mr Cake
5/14/2023
@Haris 出现错误,指出以下内容:错误 C4996“strdup”:此项的 POSIX 名称已弃用。请改用 ISO C 和C++符合标准的名称:_strdup。有关详细信息,请参阅联机帮助。
0赞
Harith
5/14/2023
@MrCake 查看 stackoverflow.com/q/7582394/20017547
0赞
Allan Wind
5/15/2023
@MrCake 对不起,我不使用 Windows。你能上班吗?_strdup()
评论
fgets(headerList, sizeof(headerList), fp);
fgets()