C言語関係掲示板

過去ログ

No.544.ファイルから成績表を作るプログラム

[戻る] [ホームページ]
No.4638

教えてくださいm(_ _)m
投稿者---彩(2003/01/26 18:27:22)


こんばんわ。
この問題で頭の中がこんがらがってしまいました。
どうか教えてください。よろしくお願いします。

問題 
 input.txt という以下のようなフォーマットのデータが入ったファイルがある。

フォーマット:
学籍番号,氏名,得点,9/24の出欠,10/01の出欠,.....,1/14の出欠

a1g01085,Hiroyuki SAKUMA,95,o,o,o,o,o,o,o,o,o,o,o,o,o
a1g01004,Kouhei IGARASHI,76,o,o,o,o,o,o,o,x,o,o,o,x,o
a1g01148,Kozue MIYASHITA,68,o,x,x,x,o,o,o,x,o,o,o,x,o
a1g01022,Takahiro KANEKO,52,o,o,o,x,o,o,o,x,o,o,o,x,o

この条件のもとで、以下のようなプログラムを作りなさい。

コマンド引数に2つファイル名を指定し、1つ目のファイルを読み込み、成績をつけて、以下のようなフォーマットで学籍番号の順に並べ替えて 2つ目のファイルに出力する。

成績のつけかたは、優先順位の高い順で
1. 出席回数が2/3未満の場合はF(資格なし)
2. 得点の記入がない場合はE(試験欠席)
3. 得点 + 出席数*0.5 が60未満の場合はD(不可)
4. 得点が60未満だが、得点 + 出席数*0.5 が60以上の場合はC
5. 得点が60以上70未満の場合はC
6. 得点が70以上80未満の場合はB
7. 得点が80以上90未満の場合はA
8. 得点が90以上の場合はAA
とする。
なお o が出席で x が欠席。また出席のフィールド数は、科目によって変わる可能性があるが、同じファイル内では同じ数になっている。
出力フォーマット:
学籍番号,氏名,得点,出席数,成績

例:プログラム名をpro2とする

% pro2 input.txt output.txt

output.txt の中身:
a1g01004,Kouhei IGARASHI,76,11,A
a1g01022,Takahiro KANEKO,52,10,D
a1g01085,Hiroyuki SAKUMA,95,13,AA
a1g01148,Kozue MIYASHITA,68,8,F

というものです。


No.4652

Re:教えてくださいm(_ _)m
投稿者------(2003/01/27 10:43:13)


何を教えればいいですか?

No.4665

Re:教えてくださいm(_ _)m
投稿者---sai(2003/01/27 14:18:48)


ほとんど全てのソースなのですが(すみません)、特に名前の部分でスペースがあったり無かったりすると、取り込み損ねている部分が出てきてしまいました。

a1g01085,Hiroyuki SAKUMA,95,o,o,o,o,o,o,o,o,o,o,o,o,o
a1g01004,KouheiIGARASHI,76,o,o,o,o,o,o,o,x,o,o,o,x,o

scanf("%s,%s,%d",str1,str2,&n);
とすると
a1g01085,Hiroyuki
a1g01004,KouheiIGARASHI
となってしまいました。
あと、出欠のカウント○×をどのようにすればいいのか分からず苦悩しています(> <)


No.4668

Re:教えてくださいm(_ _)m
投稿者------(2003/01/27 15:23:06)


#include <stdio.h>
#include <stdlib.h>
#include <string.h> 

typedef struct {
    char sNo[10];
    char sName[20];
    int  nScore;
    int  nAttend;
} STUDENT;

main()
{
    FILE *fp;
    char buff[256]; 
    char sScoreTemp[4];
    STUDENT DataStudent[100];
    int  n;
    int  nDataIndex;
    int nDataStart;
    int  nNum;

    if (( fp = fopen("input.txt","r")) == NULL )
    {
        printf("ファイルオープン失敗!");
        exit(-1);
    }

    nNum = 0;
    while( !feof(fp) )
    {
        fgets( buff, 256, fp );
        n = 0;
        nDataStart = 0;
        nDataIndex = 0;
        DataStudent[nNum].nAttend = 0;
        while( buff[n] != '\0')
        {
            if ( buff[n] == ',' || buff[n] == '\n')
            {
                nDataIndex++;
                if ( nDataIndex == 1 )
                {
                    strncpy( DataStudent[nNum].sNo, &buff[nDataStart], n - nDataStart);
                    DataStudent[nNum].sNo[n - nDataStart] = '\0';
                    nDataStart = n+1;
                }
                else if ( nDataIndex == 2 )
                {
                    strncpy( DataStudent[nNum].sName, &buff[nDataStart], n - nDataStart);
                    DataStudent[nNum].sName[n - nDataStart] = '\0';
                    nDataStart = n+1;
                }
                else if ( nDataIndex == 3 )
                {
                    strncpy( sScoreTemp, &buff[nDataStart], n - nDataStart);
                    DataStudent[nNum].nScore = atoi(sScoreTemp);
                }
                else if ( 4 <= nDataIndex && nDataIndex <= 16 )
                {
                    if ( buff[n-1] == 'o')
                    {
                        DataStudent[nNum].nAttend++;
                    }
                }
            }
            n++;
        }
        nNum++;
    }

    fclose(fp);
}


No.4696

Re:教えてくださいm(_ _)m
投稿者---かずま(2003/01/27 21:46:27)


>    while( !feof(fp) )
feof() の使い方を間違っているため、
最後のデータを2回読み込んだようになっています。
fclose() の後で、データを表示してみれば分かります。

feof() は、直前の入力処理で、データが読めなかったことを示すものであって、
feof() 以降に、データが読めることを保証するものではありません。

No.4706

Re:教えてくださいm(_ _)m
投稿者------(2003/01/28 00:35:46)


何も正しい答えを出すことが目的じゃなくて、こんな感じなりますよ
というヒントなので特にコンパイルをしていません。
こんなとこで答えを出すほうが間違っていると私は思っていますので。
(と、ほとんど言い訳・・・)

でも、本当に正しいプログラムだと本人のためにはならないのでは?

No.4698

Re:教えてくださいm(_ _)m
投稿者---sai(2003/01/27 21:54:31)


ありがとうございます。
なのですが、この出欠を成績の要素とするにはどうすればよいのでしょうか。
点数と結びつけてうまく組むことが出来ません。
成績のつけ方も含めた全体を組んではもらえませんでしょうか。お手数ですがお願いします。

No.4711

Re:教えてくださいm(_ _)m
投稿者------(2003/01/28 09:35:22)


まるで「作れないので作ってください。」って言っているみたいに感じます。
あなたがどれだけ努力してどこまでできたのか一度ソースを見せてください。


No.4712

ん〜と
投稿者---雪猫(2003/01/28 11:10:21)


明後日までに、プログラム4本作成する羽目になった雪猫です(><;)

>点数と結びつけてうまく組むことが出来ません。

って言ってるんだから、そのうまく組めなかったプログラムで良いので、
ここに公開しましょう♪
まずは、そこからですよ♪
私的には、↑の方がプログラム作成して公開してくれてますけど、
あれだけわかれば、後は簡単ですよ☆ミ

処理の分からない個所は、
/*ここに〜という処理をする*/
みたいに注釈でもつけて組んでみてはいかがでしょうか?


No.4713

Re:教えてくださいm(_ _)m
投稿者---+++(2003/01/28 11:12:01)


暇だったから作ってみました。

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 

typedef struct {
    char sNo[10];
    char sName[20];
    int  nScore;
    int  nAttend;
    char sRecord[3];
} STUDENT;

/* 読み込みデータ データ分割 */
void DataDivide( char *buff,  STUDENT *pStudent )
{
    int n = 0;
    int nDataStart = 0;
    int nDataIndex = 0;
    char sScoreTemp[4];

    pStudent->nAttend = 0;
    while( buff[n] != '\0')
    {
        if ( buff[n] == ',' || buff[n] == '\n')
        {
            nDataIndex++;
            if ( nDataIndex == 1 )
            {
                strncpy( pStudent->sNo, buff+nDataStart, n - nDataStart);
                pStudent->sNo[n - nDataStart] = '\0';
                nDataStart = n+1;
            }
            else if ( nDataIndex == 2 )
            {
                strncpy( pStudent->sName, buff+nDataStart, n - nDataStart);
                pStudent->sName[n - nDataStart] = '\0';
                nDataStart = n+1;
            }
            else if ( nDataIndex == 3 )
            {
                sScoreTemp[0] = '\0';
                strncpy( sScoreTemp, buff+nDataStart, n - nDataStart);
                if ( sScoreTemp[0] == '\0' )
                {
                    pStudent->nScore = -1;
                }
                else
                {
                    pStudent->nScore = atoi(sScoreTemp);
                }
            }
            else if ( 4 <= nDataIndex && nDataIndex <= 16 )
            {
                if ( buff[n-1] == 'o')
                {
                    pStudent->nAttend++;
                }
            }
        }
        n++;
    }
}

/* ファイル読み込み */
int ReadData( char *input, STUDENT *pStudent )
{
    FILE *fp;
    char buff[256];
    int nNum=0;

    if (( fp = fopen(input,"r")) == NULL )
    {
        printf("ファイルオープン失敗!");
        nNum = -1;
    }
    else
    {
        nNum = 0;
        while( !feof(fp) )
        {
            if ( fgets( buff, 256, fp ) != NULL )
            {
                DataDivide( buff, pStudent+nNum );
                nNum++;
            }
        }

        fclose(fp);
    }

    return nNum;
}

/* ファイル書き込み */
void WriteData( char *output, STUDENT **pStudent, int nNum )
{
    FILE *fp;

    if (( fp = fopen(output,"w")) == NULL )
    {
        printf("ファイルオープン失敗!");
    }
    else
    {
        int i;

        for( i = 0; i < nNum; i++ )
        {
            STUDENT *pTemp = *(pStudent+i);
            fprintf(fp,"%s,%s,%d,%d,%s\n",    pTemp->sNo,
                                            pTemp->sName,
                                            pTemp->nScore,
                                            pTemp->nAttend,
                                            pTemp->sRecord);
        }

        fclose(fp);
    }
}


<次に続く・・・>

No.4714

Re:教えてくださいm(_ _)m
投稿者---+++ (2003/01/28 11:12:52)


<続き・・・>

/* 成績判別 */
void AnalyzeRecord( STUDENT *pStudent )
{
    if ( (13 * (2.0 / 3.0)) > (float)pStudent->nAttend )
    {    /* 出席回数が2/3未満の場合はF(資格なし) */
        sprintf(pStudent->sRecord,"F");
    }
    else if ( 0 > pStudent->nScore )
    {    /* 得点の記入がない場合はE(試験欠席) */
        sprintf(pStudent->sRecord,"E");
    }
    else if ( 60 > pStudent->nScore+(pStudent->nAttend*0.5))
    {    /* 得点 + 出席数*0.5 が60未満の場合はD(不可) */
        sprintf(pStudent->sRecord,"D");
    }
    else if ( 60 > pStudent->nScore && 60 <= pStudent->nScore+(pStudent->nAttend*0.5))
    {    /* 得点が60未満だが、得点 + 出席数*0.5 が60以上の場合はC */
        sprintf(pStudent->sRecord,"C");
    }
    else if ( 60 <= pStudent->nScore && pStudent->nScore < 70 )
    {    /* 得点が60以上70未満の場合はC */
        sprintf(pStudent->sRecord,"C");
    }
    else if ( 70 <= pStudent->nScore && pStudent->nScore < 80 )
    {    /* 得点が70以上80未満の場合はB */
        sprintf(pStudent->sRecord,"B");
    }
    else if ( 80 <= pStudent->nScore && pStudent->nScore < 90 )
    {    /* 得点が80以上90未満の場合はA */
        sprintf(pStudent->sRecord,"A");
    }
    else
    {    /* 得点が90以上の場合はAA */
        sprintf(pStudent->sRecord,"AA");
    }
}

/* メイン */
main(int argc, char *argv[])
{
    if ( 3 != argc )
    {
        printf("引数が足りません。\n");
    }
    else
    {
        STUDENT DataStudent[100];
        STUDENT *pDisplayData[100];
        STUDENT *pTemp;

        int  nNum;

        /* データ読み込み */
        nNum = ReadData( argv[1], DataStudent );

        /* データは読めたか? */
        if ( 0 < nNum )
        {
            int i,j;
            /* 成績を判断する */
            for ( i=0; i < nNum; i++ )
            {
                AnalyzeRecord( &DataStudent[i] );
                pDisplayData[i] = &DataStudent[i];
            }

            /* データのソート */
            for ( i=0; i < nNum-1; i++ )
            {
                for ( j=i+1; j < nNum; j++ )
                {
                    int nComp = strcmp( pDisplayData[i]->sNo, pDisplayData[j]->sNo);
                    if ( nComp > 0)
                    {
                        pTemp = pDisplayData[j];
                        pDisplayData[j] = pDisplayData[i];
                        pDisplayData[i] = pTemp;
                    }
                }
            }

            printf(" 元データ                             書き込みデータ\n");
            for ( i = 0;i < nNum;i++)
            {
                printf("[%-12s %-20s]  [%-12s %s %-2s]\n"
                    ,DataStudent[i].sNo,DataStudent[i].sName
                    ,pDisplayData[i]->sNo,pDisplayData[i]->sName
                    ,pDisplayData[i]->sRecord);
            }

            /* データ書き込み */
            WriteData( argv[2], pDisplayData, nNum );
        }
    }
}


No.4716

Re:教えてくださいm(_ _)m
投稿者---かずま(2003/01/28 11:17:00)


> なのですが、この出欠を成績の要素とするにはどうすればよいのでしょうか。
> 点数と結びつけてうまく組むことが出来ません。
#include <stdio.h>

struct { char *id, *name; int score, attend; } data[] = {
    { "a1g01004", "Kouhei IGARASHI", 76, 11 },
    { "a1g01022", "Takahiro KANEKO", 52, 10 },
    { "a1g01085", "Hiroyuki SAKUMA" ,95, 13 },
    { "a1g01148", "Kozue MIYASHITA", 68,  8 },
};

const char *get_grade(int score, int attend, int days)
{
    if (attend * 3 < days * 2) return "F";
    if (score < 0)             return "E";
    if (score + attend/2 < 60) return "D";
    if (score < 70) return "C";
    if (score < 80) return "B";
    if (score < 90) return "A";
    return "AA";
}

int main(void)
{
    int i, n = sizeof data / sizeof *data;

    for (i = 0; i < n; i++)
        printf("%s,%s,%d,%d,%s\n", data[i].id, data[i].name,
            data[i].score, data[i].attend,
            get_grade(data[i].score, data[i].attend, 13));
    return 0;
}


No.4718

質問内容は具体的に書いてください。
投稿者---のぞき見(2003/01/28 11:18:40)


>なのですが、この出欠を成績の要素とするにはどうすればよいのでしょうか。
>点数と結びつけてうまく組むことが出来ません。

点数と出欠をどのように結び付けたいのですか??
あなたの質問の仕方は非常に抽象過ぎて全く理解ができない。

もっと具体的に何をどのようにしたいのか書いてください。