提问人:ecjb 提问时间:2/25/2023 最后编辑:ecjb 更新时间:2/25/2023 访问量:51
无法将 csv 加载到最后一个成员作为 char 数组的结构中
Trouble loading a csv into a struct where the last member is as an array of char
问:
我想读取一个 csv 文件并将其加载到结构数组中。我使用了我在 youtube 和 github (https://github.com/portfoliocourses/c-example-code/blob/main/csv_to_struct_array.c) 上找到的代码。现在我想将结构的所有成员更改为字符数组(或字符串)。如果我按顺序更改每个结构(成员和至少),这将有效,但如果我将成员更改为字符数组,则会出现错误消息。我怀疑它 si 因为在循环过程中文件中的字符有问题。我该如何解决问题?type
age
average
File format incorrect
EOF
while (!feof(file));
以下是原始代码:
/*******************************************************************************
*
* Program: Read CSV File Data To An Array Of Structs
*
* Description: Example of reading CSV file data into an array of structs in C.
*
* YouTube Lesson: https://www.youtube.com/watch?v=rbVt5v8NNe8
*
* Author: Kevin Browne @ https://portfoliocourses.com
*
*******************************************************************************/
#include <stdio.h>
// A struct for representing student data in a file formatted like this:
//
// U,Virat Kohli,23,95.6
// U,Serena Williams,22,83.2
// G,Wayne Gretzky,19,84.2
//
// with a "student type" (e.g. undergraduate, graduate) single character,
// followed by the student's name, age and then average.
//
typedef struct
{
// members for the student's type, name, age and average
char type;
char name[50];
int age;
double average;
} Student;
int main(void)
{
// file pointer variable for accessing the file
FILE *file;
// attempt to open file.txt in read mode to read the file contents
file = fopen("file.txt", "r");
// if the file failed to open, exit with an error message and status
if (file == NULL)
{
printf("Error opening file.\n");
return 1;
}
// array of structs for storing the Student data from the file
Student students[100];
// read will be used to ensure each line/record is read correctly
int read = 0;
// records will keep track of the number of Student records read from the file
int records = 0;
// read all records from the file and store them into the students array
do
{
// Read a line/record from the file with the above format, notice in
// particular how we read in the student's name with %49[^,] which matches
// up to 49 characters NOT including the comma (so it will stop matching
// at the next comma). The name member can store 50 characters, so
// factoring in the NULL terminator this is the maximum amount of characters
// we can read in for a number. fscanf() will return the number of values
// it was able to read successfully which we expect to be 4, and we store
// that into read.
//
read = fscanf(file,
"%c,%49[^,],%d,%lf\n",
&students[records].type,
students[records].name,
&students[records].age,
&students[records].average);
// if fscanf read 4 values from the file then we've successfully read
// in another record
if (read == 4) records++;
// The only time that fscanf should NOT read 4 values from the file is
// when we've reached the end of the file, so if fscanf did not read in
// exactly 4 values and we're not at the end of the file, there has been
// an error (likely due to an incorrect file format) and so we exit with
// an error message and status.
if (read != 4 && !feof(file))
{
printf("File format incorrect.\n");
return 1;
}
// if there was an error reading from the file exit with an error message
// and status
if (ferror(file))
{
printf("Error reading file.\n");
return 1;
}
} while (!feof(file));
// close the file as we are done working with it
fclose(file);
// print out the number of records read
printf("\n%d records read.\n\n", records);
// print out each of the records that was read
for (int i = 0; i < records; i++)
printf("%c %s %d %.2f\n",
students[i].type,
students[i].name,
students[i].age,
students[i].average);
printf("\n");
return 0;
}
修改后的代码如下:
#include <stdio.h>
typedef struct
{
//char type; \\original commented code
//char name[50]; \\original commented code
//int age; \\original commented code
//double average; \\original commented code
char type[50];
char name[50];
char age[50];
char average[50];
} Student;
int main(void)
{
FILE *file;
file = fopen("file.txt", "r");
if (file == NULL)
{
printf("Error opening file.\n");
return 1;
}
Student students[100];
int read = 0;
int records = 0;
do
{
read = fscanf(file,
//"%c,%49[^,],%d,%lf\n" \\original commented code
"%49[^,],%49[^,],%49[^,],%49[^,]\n",
students[records].type,
students[records].name,
students[records].age,
students[records].average);
//students[records].average);
if (read == 4) records++;
if (read != 4 && !feof(file))
{
printf("File format incorrect.\n");
return 1;
}
if (ferror(file))
{
printf("Error reading file.\n");
return 1;
}
} while (!feof(file));
fclose(file);
printf("\n%d records read.\n\n", records);
for (int i = 0; i < records; i++)
//printf("%c %s %d %.2f\n", \\original commented code
printf("%s %s %s %.s\n",
students[i].type,
students[i].name,
students[i].age,
students[i].average);
printf("\n");
return 0;
}
编辑 1我更改了" %49[^,],%49[^,],%49[^,],%49[^\n]",
并得到以下输出:
3 records read.
U Virat Kohli 23
U Serena Williams 22
G Wayne Gretzky 19
从某种意义上说,有一个改进,即可以解析文件,但最后一列(或每行最后一个逗号后面的项目)消失了,因为它应该显示:
3 records read.
U Virat Kohli 23 95.60
U Serena Williams 22 83.20
G Wayne Gretzky 19 84.20
这是修改后的版本的源代码
#include <stdio.h>
typedef struct
{
//char type; \\original commented code
//char name[50]; \\original commented code
//int age; \\original commented code
//double average; \\original commented code
char type[50];
char name[50];
char age[50];
char average[50];
} Student;
int main(void)
{
FILE *file;
file = fopen("file.txt", "r");
if (file == NULL)
{
printf("Error opening file.\n");
return 1;
}
Student students[100];
int read = 0;
int records = 0;
do
{
read = fscanf(file,
//"%c,%49[^,],%d,%lf\n" \\original commented code
//"%49[^,],%49[^,],%49[^,],%49[^,\n]",
" %49[^,],%49[^,],%49[^,],%49[^\n]",
students[records].type,
students[records].name,
students[records].age,
students[records].average);
//students[records].average);
if (read == 4) records++;
if (read != 4 && !feof(file))
{
printf("File format incorrect.\n");
return 1;
}
if (ferror(file))
{
printf("Error reading file.\n");
return 1;
}
} while (!feof(file));
fclose(file);
printf("\n%d records read.\n\n", records);
for (int i = 0; i < records; i++)
//printf("%c %s %d %.2f\n", \\original commented code
printf("%s %s %s %.s\n",
students[i].type,
students[i].name,
students[i].age,
students[i].average);
printf("\n");
return 0;
}
使用源记录(从原始代码复制):file.txt
U,Virat Kohli,23,95.6
U,Serena Williams,22,83.2
G,Wayne Gretzky,19,84.2
答:
1赞
Vlad from Moscow
2/25/2023
#1
重写格式字符串,如
" %49[^,],%49[^,],%49[^,],%49[^\n]",
注意格式字符串中的前导空格。它允许跳过空格字符。
我假设整个记录不以逗号结尾。
另一种方法是声明一个足够大的字符数组来存储文件中的记录,并使用 代替 。然后,您可以使用 或 分析获取的记录。fgets
scanf
strtok
sscanf
同样在电话中printf
printf("%s %s %s %.s\n",
students[i].type,
students[i].name,
students[i].age,
students[i].average);
转换说明符不正确。相反,只需写 .%.s
%s
评论
0赞
ecjb
2/25/2023
感谢您@VladfromMoscow的回答。我按照您的建议更改了代码。现在可以解析文件,并且有一个打印的输出,但每行的最后一项(在最后一个逗号之后)除外。我编辑了问题以提出问题
0赞
Vlad from Moscow
2/25/2023
@ecjb 显示源记录的示例。
0赞
ecjb
2/25/2023
我在问题的编辑结束时复制了编辑版本的源代码。我错过了什么吗?
0赞
Vlad from Moscow
2/25/2023
@ecjb 我没有看到源记录。而且我无法重现您的输出。显示源记录。
0赞
ecjb
2/25/2023
感谢您的评论:我在问题末尾添加了(从原始代码复制)(就在源代码的编辑版本之后)。如果还不清楚,请告诉我file.txt
评论
printf("File format incorrect: line %d.\n", records);