英文:
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 <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;
}
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).
-
Use symbolic constants instead of magic values. When you do that it becomes apparent that it's odd that
NAME_LEN
>LINE_LEN
. -
(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. -
Added error handling for
strtok()
. Each line is a natural synchronization point so it's easy to skip invalid lines. -
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'\n'
but the data line a','
. -
(Not fixed) Consider using
strtol()
instead of aatoi()
so you can detect errors.atoi()
returns 0 on error.
#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]);
}
and example session:
name:duck hp:20 damage:5
name:cat hp:30 damage:10
name:giraffe hp:100 damage:20
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论