我想尝试做的是解析一个CSV,其中包含一个人的名字、姓氏和体重,以及一个结构数组中的这些数据。这是我到目前为止的代码。我能够解析并打印出CSV的值,但我不太确定如何将这些值存储到结构数组中。我希望能够从person. c访问CSV的值,但实际上是从vector. c中读取的,这意味着我必须从vector. c中的person. c中调用函数readCSV(),你们谁能帮我一下吗?
//vector.h
#ifndef VECTOR_H_
#define VECTOR_H_
#include "person.h"
typedef struct
{
Person *personArray;
int sizeArray;
int count;
}Vector;
//person.h
#ifndef PERSON_H_
#define PERSON_H_
typedef struct
{
const char *firstName, *lastName;
double weight;
}Person;
//vector.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "vector.h"
void readPerson(Vector *v)
{
readCSV(v->personArray);
}
//person.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "person.h"
void initialize(Vector *v)
{
v->sizeArray = 10;
v->count = 0;
v->personArray = (City*) malloc(v->sizeArray*sizeof(City));
}
void readCSV(Person* person)
{
FILE * fp;
char line[1024];
int i = 0;
fp = fopen("mycsvfile.csv","r");
while(fgets(line,sizeof(line),fp))
{
person->firstName = strtok(line,",");
person->lastName = strtok(NULL,",");
person->weight = atof(strtok(NULL,","));
printf("%s %s %f\n",person->firstName, person->lastName, person->weight);
}
fclose(fp);
}
//main.c
#include<stdio.h>
#include<stdlib.h>
#include "vector.h"
int main()
{
Vector people;
initialize(&people);
readPerson(&people);
return 0;
}
字符串
2条答案
按热度按时间s2j5cfk01#
如下所示:
字符串
ep6jt1vc2#
您的代码有两个主要问题:
1.在readCSV中,你有一个循环来读取CSV中的所有行,但是你阅读的所有数据总是存储在同一个(非数组)变量中。你需要传递一个Vector,而不是一个Person来读取CSV,并使用people->personArray[index].some_field来存储数据。
1.每次调用fgets()时,它都会覆盖第[1024]行。在再次调用fgets()之前,需要复制解析后的数据。为此,我使用了strdup。
在你的代码中,打印工作正常,因为你在调用fgets()之前打印了解析后的数据,但是问题2阻止了你将解析和打印分开。
这段代码修复了这两个问题,并将打印移到另一个函数中进行最小的编辑。我将person.c重命名为vector.c,因为那里的函数将矢量作为一个整体来处理,而不是单个人。
字符串
这些代码是有效的,应该可以让你继续你的工作或任务。但是,为了成为值得生产状态的高质量代码,还有很多问题需要解决:
1.释放使用的内存。当不再使用时,需要释放用malloc、strdup等分配的内存。在这个小程序中,当main退出时,它将被C运行时释放,但当你的代码成为一个更大项目的一部分时,它将是一个重要的问题。最好现在就习惯它。
1.处理不受约束的输入。尝试使用包含11个条目的输入文件运行程序,它可能会崩溃或表现出未定义的行为。这是因为我们在初始化中分配了10个条目(Vector* v)。要解决这个问题,你可以使用一个可增长的数据类型,比如链表。或者你可以对文件进行两次解析;一旦丢弃数据以确定其具有多少条目,则分配该数组,然后分配第二个数组以实际读取和存储数据。
1.处理不正确的输入。您需要指定CSV文件的格式。是否允许空字段?最大行长度?并验证输入文件的正确性,如果没有解析而不是阅读不正确的输入,则会出现错误。如果文件不存在或无法读取,会发生什么情况?
1.使你的代码通用化。readCSV(Vector* people)应该变成readCSV(Vector*,const char* filename)。你可以在命令行中使用main(int argc,char* argv[])而不是使用常量字符串来读取文件名。
1.注意strtok()和fgets()的行为!使用fgets()读取的行(可能最后一个除外)将以“\n”结尾。在以“83.5\n”结尾的行中,最后一个标记将是“83.5\n”。请注意此处的回车符。这可能不是您想要的。在您的代码中,它可以工作,因为atof在“\n”处停止解析。如果您不想要\n您可以在您的内标识中使用strtok(line_or_NULL,“,\n”)
1.正确处理你的Vector状态。如果你调用readCSV()两次会发生什么?如果initialize()被调用了两次会发生什么?最安全的做法是检测它,因为它是一个快速的检查,如果调用不正确,程序会中止并返回错误代码,或者返回错误代码。
1.文档代码。每个函数的头,解释它的作用,参数和返回的内容。列出前置条件和后置条件是非常重要的,比如允许或不允许在同一个Vector上调用两次initialize。
1.单元测试。