我正在尝试做一个程序,从csv文件中获取数据/值并打印出来,但有些部分我还在纠结

aiqt4smr  于 2023-05-20  发布在  其他
关注(0)|答案(1)|浏览(104)

我正在尝试编写一个程序来读取一个看起来像这样的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文件的头部分(名称,hp,损坏)应存储到名为“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;
}

这是我到目前为止的代码。我相信我能够将每个头值放入hd 1、hd2和hd 3中,但我不确定如何将它们放入数组中并在以后使用。我也知道打印部分现在是错误的,但我这样写只是为了测试每个头的值是否打印良好。
另外,原始的csv文件是韩语的,但为了简单起见,我将它们翻译成了英语。所以数组的大小可能与我想要实现的不匹配。
任何帮助将不胜感激!

vbopmzt1

vbopmzt11#

您假定了一个固定的头顺序,所以这些需求对我来说没有什么意义(与阅读头然后使用该信息将列号Map到结构成员相反)。
1.使用符号常量而不是魔术值。当你这样做的时候,很明显,NAME_LEN> LINE_LEN是奇怪的。
1.(部分修复)不要读取超过MONSTERS的记录,以防止缓冲区溢出。我没有,但可能想生成一个警告,如果有更多的数据比空间在您的数组。
1.添加了strtok()的错误处理。每一行都是一个自然的同步点,因此很容易跳过无效的行。
1.由于标题和数据行的解析方式相同,只是使用方式不同。这也修复了第3个strtok()预期为'\n'但数据线为','的缺陷。
1.(未修复)考虑使用strtol()而不是atoi(),以便可以检测错误。atoi()在出错时返回0。

#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

相关问题