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

huangapple go评论61阅读模式
英文:

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

问题

It seems like you want assistance with your C code for reading and processing a CSV file. To address your specific request, I'll provide a translation of the code comments and variable names from English to Chinese without adding any extra content. Here's the translated code:

#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("打开文件错误\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("名称:%s 生命值:%d 伤害:%d\n",
            monsters[i].name, monsters[i].hp, monsters[i].damage);
    }

    fclose(fp);
    return 0;
}

Please note that this is a direct translation of the comments and variable names, and I have not made any changes to the logic or structure of your code. If you have any further questions or need additional assistance with your code, feel free to ask.

英文:

I'm trying to make a program that reads a csv file that looks like this:

name,hp,damage

duck,20,5

cat,30,10

giraffe,100,20

And I want to print the above csv file like this:

name:duck hp:20 damage:5

name:cat hp:30 damage:10

name:giraffe hp:100 damage:20

The requirement is that the header part of the csv file (name,hp,damage) should be stored into an array called 'header' and when printing the csv file the array 'header' must be used.

#define _CRT_SECURE_NO_WARNINGS
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

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(&quot;entityData.csv&quot;, &quot;r&quot;);
    if (!fp) {
        printf(&quot;Error opening file\n&quot;);
        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, &quot;,&quot;);
    strncpy(monsters[num_records].name, hd1, 20);
    hd2 = strtok(NULL, &quot;,&quot;);
    hd3 = strtok(NULL, &quot;\n&quot;);
    


    while (fgets(line, sizeof(line), fp))
    {
        char* token = strtok(line, &quot;,&quot;); 
        strncpy(monsters[num_records].name, token, 20);

        token = strtok(NULL, &quot;,&quot;);
        monsters[num_records].hp = atoi(token);

        token = strtok(NULL, &quot;,&quot;);
        monsters[num_records].damage = atoi(token);

        num_records++;
    }

    for (int i = 0; i &lt; num_records; i++) {
        printf(&quot;name:%s hp:%d damage:%d\n&quot;,
            monsters[i].name, monsters[i].hp, monsters[i].damage);
    }

    fclose(fp);
    return 0;
}

Here is my code so far. I believe that I was able to get each header values into hd1, hd2, and hd3, but I'm not sure how those can be put into an array and used later. I also know that the print part is wrong right now, but I wrote it like that just to test if the values of each headers are printing well.

Also, the original csv file is in Korean, but I translated them into English for simplicity. So the array sizes might not match what I'm trying to achieve.

Any help would be greatly appreciated!

答案1

得分: 1

以下是你提供的代码的翻译:

// 假设一个固定的标题顺序,所以对我来说,这些要求有点毫无意义(与读取标题相对,然后使用该信息将列号映射到结构成员)。

1. 使用符号常量而不是魔术值。当你这样做时,就会显得很奇怪,`NAME_LEN` > `LINE_LEN`。

2. (部分修复)不要读取超过 `MONSTERS` 条记录以防止缓冲区溢出。我没这样做,但可能会希望在数组中的空间不足以容纳更多数据时生成警告。

3.  `strtok()` 添加错误处理。每行都是一个自然的同步点,所以很容易跳过无效的行。

4. 由于标题和数据行以相同的方式解析,只是用法不同。这也修复了第3 `strtok()` 预期为 `'\n'` 但数据行为 `','` 的缺陷。

5. (未修复)考虑使用 `strtol()` 而不是 `atoi()`,这样你可以检测错误。`atoi()` 在错误时返回0

```c
#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("打开文件错误\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 在 \"%s\" 处失败\n", line);
            num_records--;
            continue;
        }
        // 标题
        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 失败\n");
                return 1;
            }
            continue;
        }
        // 数据
        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

如果你需要进一步的帮助,请随时告诉我。

英文:

You assume a fixed header order so the requirements make little senese to me (opposed to reading the header then use that information to map a column number to a struct member).

  1. Use symbolic constants instead of magic values. When you do that it becomes apparent that it's odd that NAME_LEN > LINE_LEN.

  2. (Partial fix) Don't read more than MONSTERS records to prevent a buffer overflow. I didn't but may want to generate a warning if there is more data than space in your array.

  3. Added error handling for strtok(). Each line is a natural synchronization point so it's easy to skip invalid lines.

  4. As the header and data lines are parsing the same way, only used differently. This also fixes the defect with the 3rd strtok() expecting a &#39;\n&#39; but the data line a &#39;,&#39;.

  5. (Not fixed) Consider using strtol() instead of a atoi() so you can detect errors. atoi() returns 0 on error.

#define _POSIX_C_SOURCE 200809L // strdup()
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#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(&quot;entityData.csv&quot;, &quot;r&quot;);
if (!fp) {
printf(&quot;Error opening file\n&quot;);
return 1;
}
char *header[VALUES] = { 0 };
Monster monsters[MONSTERS];
int num_records = -1;
for(; num_records &lt; MONSTERS; num_records++) {
char line[LINE_LEN];
if(!fgets(line, sizeof(line), fp))
break;
char *name = strtok(line, &quot;,&quot;);
char *hp = strtok(NULL, &quot;,&quot;);
char *damage = strtok(NULL, &quot;\n&quot;);
if(!name || !hp || !damage) {
fprintf(stderr, &quot;strtok failed at \&quot;%s\&quot;\n&quot;, 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, &quot;strdup failed\n&quot;);
return 1;
}
continue;
}
// data
strncpy(monsters[num_records].name, name, NAME_LEN);
if(LINE_LEN &gt;= NAME_LEN)
monsters[num_records].name[NAME_LEN - 1] = &#39;\0&#39;;
monsters[num_records].hp = atoi(hp);
monsters[num_records].damage = atoi(damage);
}
for (int i = 0; i &lt; num_records; i++) {
printf(&quot;%s:%s %s:%d %s:%d\n&quot;,
header[0],
monsters[i].name,
header[1],
monsters[i].hp,
header[2],
monsters[i].damage);
}
fclose(fp);
for(int i = 0; i &lt; VALUES; i++)
free(header[i]);
}

and example session:

name:duck hp:20 damage:5

name:cat hp:30 damage:10

name:giraffe hp:100 damage:20

huangapple
  • 本文由 发表于 2023年5月14日 15:02:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76246250.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定