哪个是填充该结构的最佳方法?

时间:2010-11-23 14:08:51

标签: c

对于家庭作业的分配,我需要填写一份学生结构列表,如下所示:

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()

4 个答案:

答案 0 :(得分:2)

我会按顺序排列:

  • 首先阅读整行
  • 然后检查字段数是否正确(对于您的示例,计数;应该没问题)并处理错误情况(跳过行或停止解析?)
  • 然后将行拆分为char*[](您可以通过放置'\0'并直接使用字符串或创建新字符串来实现)
  • 然后检查必填字段的正确性(预科是一个数字,生日是约会等)
  • 然后填充真正的结构(你可以使用strcpystrdup或根据你的需要直接复制字符串的指针)

答案 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 ] );
}

考虑到缺少一些步骤。但是这个骨架应该给你一个很好的起点。

希望这有帮助。