无法将 csv 加载到最后一个成员为 char 数组的结构中

问题描述 投票:0回答:1

我想读取一个 csv 文件并将其加载到一个结构数组中。我使用了在 youtube 和 github 上找到的代码 (https://github.com/portfoliocourses/c-example-code/blob/main/csv_to_struct_array.c)。现在我想将结构的所有成员更改为字符数组(或字符串)。如果我按顺序更改每个结构(至少成员

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

c struct scanf eof conversion-specifier
1个回答
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
.

© www.soinside.com 2019 - 2024. All rights reserved.