对于家庭作业的分配,我需要填写一份学生结构列表,如下所示:
struct Student {
int matriculationNumber;
char *firstName;
char *lastName;
char *birthday;
double averageGrage;
}
必须从.csv
文件中读取实际数据,并且看起来像是
2345678;梅耶尔;汉斯; 1985年12月10日; 2,4-
1234567;穆勒;弗里茨; 1990年5月17日; 1,9
要读取数据,应使用fgetc()
。
现在,问题是如何实际填写结构的字段以及如何处理异常条件(即意外EOF
;例如,如果一行不包含字段birthday
或字段averageGroup
)。
这就是我如何直观地做到这一点(这很可能是错误的方式; - )):
Student student;
if (fillMatriculationNumber(&student, fp) == -1) { // return -1 on failure or EOF
goto failure;
}
if (fillFirstName(&student, fp) == -1) {
goto failure;
}
if (fillLastName(&student, fp) == -1) {
goto failure;
}
if (fillBirthday(&student, fp) == -1) {
goto failure;
}
if (fillAverageGrade(&student, fp) == -1) {
goto failure;
}
// OK
:failure
// print a message about what's wrong, and exit()
答案 0 :(得分:2)
我会按顺序排列:
;
应该没问题)并处理错误情况(跳过行或停止解析?)char*[]
(您可以通过放置'\0'
并直接使用字符串或创建新字符串来实现)strcpy
,strdup
或根据你的需要直接复制字符串的指针)答案 1 :(得分:1)
由于fgetc()中存在压力,您可以稍微更改一下代码。
while(!feof(fp)) { readRecordSuccess = 0; if (fillMatriculationNumber(&student, fp) != -1) { // return -1 on failure or EOF if (fillFirstName(&student, fp) != -1) { if (fillLastName(&student, fp) != -1) { if (fillBirthday(&student, fp) != -1) { if (fillAverageGrade(&student, fp) != -1) { readRecordSuccess = 1; } } } } } if(readRecordSuccess == 0) { /* may clean already filled structure(s) */ break; } /* * the structure will be overwritten in the next iteration * take proper measure */ }
答案 2 :(得分:0)
将结构中的指针字段初始化为空指针;正如评论中所指出的,memset在这里不是正确的选择 - 使用c99方式或明确地为每个字段做。
如果由于某种原因读取字段失败,则应释放已分配的字段。例如,如果读取average
对学生失败并且您决定忽略该学生的记录,则应释放他的name
字段以防止内存泄漏(当然,假设它们是malloc'ed)。
答案 3 :(得分:0)
我会读取每个CSV行,然后将其存储在Student结构中。
const unsigned int MaxFields = 5;
const unsigned int MaxContents = 80;
void readRow(FILE * f, char dataRow[MaxFields][MaxContents])
{
int c;
unsigned int i;
char buffer[MaxContents];
int pos;
int field;
// Empty all fields
for(i = 0; i < MaxFields; ++i) {
dataRow[ i ][ 0 ] = '\0';
}
// Read rows
buffer[ 0 ] = '\0';
c = fgetc( f );
pos = 0;
field = 0;
while( c != EOF
&& c != '\n' )
{
if ( c != ';' ) {
buffer[ pos++ ] = c;
} else {
buffer[ pos ] = '\0';
strcpy( dataRow[ field++ ], buffer );
buffer[ 0 ] = '\0';
pos = 0;
}
c = fgetc( f );
}
}
这样,您正在读取字符串向量中的内容。字符串向量初始化为空字符串,因此如果一个字段为空或缺失,则没有问题。
读取一行后,您可以将其存储在Student结构中:
char * safeStrDup(const char * src)
{
char * toret = strdup( src );
if ( toret == NULL ) {
fprintf( stderr, "Not enough memory\n" );
exit( EXIT_FAILURE );
}
return toret;
}
void store(Student *s, char dataRow[MaxFields][MaxContents])
{
s->matriculationNumber = atoi( dataRow[ 0 ] );
s->firstName = safeStrDup( dataRow[ 1 ] );
s->lastName = safeStrDup( dataRow[ 2 ] );
s->birthday = safeStrDup( dataRow[ 3 ] );
s->averageGrage = atof( dataRow[ 4 ] );
}
考虑到缺少一些步骤。但是这个骨架应该给你一个很好的起点。
希望这有帮助。