C Primer 5th - 任务14-6

时间:2012-03-08 14:02:04

标签: c

文本文件包含有关垒球队的信息。每行的数据排列如下:

  

4 Jessie Joybat 5 2 1 1

第一项是玩家的号码,方便地在0-18范围内。第二项是玩家的名字,第三项是玩家的姓氏。每个名字都是一个单词。下一项是球员在击球时的正式时间,然后是击球,步行和击球(RBIs)的次数。该文件可能包含多个游戏的数据,因此同一个玩家可能拥有多行数据,并且这些行之间可能存在其他玩家的数据。编写一个将数据存储到结构数组中的程序。该结构应该有成员来代表名字和姓氏,击球,击球,步行和打点(跑步击球)和击球平均值(稍后计算)。您可以将播放器编号用作数组索引。程序应该读取到文件结尾,并且应该保持每个玩家的累计总数。

棒球统计世界是一个参与其中的。例如,基于错误的步行或到达基础不算作击球但可能产生RBI。但是,如下所述,所有这个程序所要做的就是读取和处理数据文件,而不必担心数据的真实性。

程序进行的最简单方法是将结构内容初始化为零,将文件数据读入临时变量,然后将它们添加到相应结构的内容中。程序读完文件后,应计算每个玩家的击球平均值并将其存储在相应的结构成员中。击球平均数是通过将球员的累计命中数除以累计击球数来计算的;它应该是一个浮点计算。然后,程序应显示每个玩家的累积数据以及显示整个团队的综合统计数据的行。


team.txt(我正在使用的文本文件):

4 Jessie Joybat 5 2 1 1
4 Jessie Joybat 7 3 5 3
7 Jack Donner 6 3 1 2
11 Martin Garder 4 3 2 1
15 Jaime Curtis 7 4 1 2
2 Curtis Michel 3 2 2 3
9 Gillan Morthim 9 6 6 7
12 Brett Tyler 8 7 4 3
8 Hans Gunner 7 7 2 3
14 Jessie James 11 2 3 4 
12 Brett Tyler 4 3 1 3

由于我是C语言的初学者,要么我误解了最初提出的任务,要么是不公平的(我相信前者就是这种情况)。我迷失了,以至于我无法想象如何通过索引(玩家编号)的每个数据标准来填写,跟踪他是否有多个游戏,计算并获取蝙蝠平均值和然后打印。

到目前为止我所拥有的是:

#define LGT 30
struct profile {
     int pl_num;
     char name[LGT];
     char lname[LGT];
     int atbat[LGT/3];
     int hits[LGT/3];
     int walks[LGT/3];
     int runs[LGT/3];
     float batavg;
};

//It's wrong obviously but it's a starting point
int main(void)
{
    FILE *flx;
    int i,jc,flow=0;
    struct profile stat[LGT]={{0}};

    if((flx=fopen("team.txt","r"))==NULL) {
        fprintf(stderr,"Can't read file team!\n");
        exit(1);      
    }

    for( jc = 0; jc < 11;  jc++) {
        fscanf(flx,"%d",&i);
        stat[i].pl_num=i;

        fscanf(flx,"%s",&stat[i].name);
        fscanf(flx,"%s",&stat[i].lname);

        fscanf(flx,"%d",&stat[i].atbat[flow]);
        fscanf(flx,"%d",&stat[i].hits[flow]);
        fscanf(flx,"%d",&stat[i].walks[flow]);
        fscanf(flx,"%d",&stat[i].runs[flow]);
        flow++;
    }
}

3 个答案:

答案 0 :(得分:1)

建议1:不要声明像atbat[LGT/3]这样的数组。

建议2:您可以一次性阅读整行,而不是多个fscanf

建议3:由于玩家数量有限且玩家数量范围较大(0-18),因此使用该玩家编号作为结构阵列的索引是一个好主意。

建议4:由于你需要每个玩家的累积数据(不需要存储他的历史记录点),所以你不需要整数数组,只需要一个整数来表示总数。

所以:

#include <stdio.h>

#define PLAYERS_NO  19

typedef struct  
{
     char name[20+1];
     char lastName[25+1];
     int atbat;
     int hits;
     int walks;
     int runs;
     float batavg;
} Profile;



int main(int argc, char** argv)
{
    Profile stats[PLAYERS_NO];
    int i;
    FILE* dataFile;

    int playerNo;
    Profile tmpProfile;
    int games = 0;


    for(i=0; i<PLAYERS_NO; ++i)
    {
        stats[i].name[0] = '\0';
        stats[i].lastName[0] = '\0';
        stats[i].atbat = 0;
        stats[i].hits = 0;
        stats[i].walks = 0;
        stats[i].runs = 0;
    }

    dataFile = fopen("team.txt", "r");
    if ( dataFile == NULL )
    {
        fprintf(stderr, "Can't read file team!\n");
        exit(1);    
     }

     for(i=0; i<PLAYERS_NO && !feof(dataFile); ++i, ++games)
     {
        fscanf(dataFile, "%d", &playerNo);
        if ( playerNo <0 || playerNo > PLAYERS_NO )
        {
           fprintf(stderr, "Player number out of range\n");
           continue;
        }

        fscanf(dataFile, "%s %s %d %d %d %d", 
            &tmpProfile.name,
            &tmpProfile.lastName,
            &tmpProfile.atbat,
            &tmpProfile.hits,
            &tmpProfile.walks,
            &tmpProfile.runs);

        printf("READ: %d %s %s %d %d %d %d\n", 
            playerNo,
            tmpProfile.name,
            tmpProfile.lastName,
            tmpProfile.atbat,
            tmpProfile.hits,
            tmpProfile.walks,
            tmpProfile.runs);


        strcpy(stats[playerNo].name, tmpProfile.name);
        strcpy(stats[playerNo].lastName, tmpProfile.lastName);

        stats[playerNo].atbat += tmpProfile.atbat;
        stats[playerNo].hits += tmpProfile.hits;
        stats[playerNo].walks += tmpProfile.walks;
        stats[playerNo].runs += tmpProfile.runs;
    }

    /* exercise: compute the average */
    fclose(dataFile);

    for(i=0; i<PLAYERS_NO; ++i)
    {
        if ( stats[i].name[0] == '\0' )
            continue;

        printf("%d %s %s %d %d %d %d\n",
            i,
            stats[i].name,
            stats[i].lastName,
            stats[i].atbat,
            stats[i].hits,
            stats[i].walks,
            stats[i].runs);
    }

    return 0;
}

答案 1 :(得分:0)

编程的第一条规则:分而治之。

因此,您需要识别个别操作。一个这样的操作是“加载一行输入”,另一个是“查找玩家”。如果你有一些这样的操作(你会有更多的操作),你可以开始构建你的程序:

while( more_input ) {
    row = load_one_row()
    player = find_player( row.name )
    if( !player ) {
        player = create_player( row.name )
        add_player( player )
    }

    ... do something with row and player ...
}

当你拥有它时,你可以开始编写所有函数。

这里重点是编写测试用例。从简单的输入开始并测试代码以读取一行。你得到了正确的结果吗?

如果是这样,请测试代码以查找/创建播放器。

测试用例确保您可以忘记已经有效的代码。

为此使用Check之类的框架。

答案 2 :(得分:0)

如果我这样做,我会从一个只保存一组“数据”的结构开始,然后创建一个这些结构的数组:

struct profile {
     char name[NAMELEN];
     char lname[NAMELEN];
     int atbat;
     int hits;
     int walks;
     int runs;
     float batavg;
};

由于您使用播放器的编号作为数组的索引,因此您无需将其存储到结构中。

我认为这会简化问题。您不需要为单个播放器存储多个数据项 - 当您获得重复时,您只需忽略一些新数据(如名称,应该相同)并总结其他数据(例如, - 蝙蝠,命中)。