ファイルとか構造体とか

### 内容

- 左から順に学生番号,英語,数学,国語,理科,社会が書かれているcsvファイルが与えられている
- 各科目について90点以上ならA+,80以上ならA……として、各学生の成績を科目ごとに異なるファイルへ出力するプログラムを作成する

```ruby:score.csv
1001,99,83,94,100,86
1002,42,15,61,44,57
1003,37,75,65,28,49
1004,58,52,51,62,55
1005,83,90,33,27,10
1006,41,27,36,85,86
1007,90,56,83,48,95
1008,12,89,24,78,21
```

- ここからソースコード

```ruby:kadai.c

#include<stdio.h>
#define Students 8

typedef struct{
    int num;
    int score[5];
}student;

int Dealer(char *filename,int whatsb,student data[]);
FILE *fp;
int main(void){
    char savefile[][18] = {"grade_Eng.csv","grade_Math.csv","grade_Japa.csv","grade_Sci.csv","grade_Civ.csv"};
    student data[Students];
    int i;
    if((fp = fopen("score.scv","r"))==NULL)return-1;
    for(i=0;i<Students;i++){
        fscanf( fp, "%d,%d,%d,%d,%d,%d\n",&data[i].num,&data[i].score[0],&data[i].score[1],&data[i].score[2],&data[i].score[3],&data[i].score[4]);
    }
    fclose(fp);
    for(i=0;i<5;i++){
        if(Dealer(savefile[i],i,data)==-1)break;
    }
    return 0;
}
int Dealer(char *filename,int whatsb,student data[]){
    int i;
    if( (fp = fopen( filename, "w" )) == NULL)return -1;
    for(i=0;i<Students;i++){
        if(data[i].score[whatsb]<0 || 100 < data[i].score[whatsb])fprintf(fp,"%d,%s\n",data[i].num,"X");
            switch(data[i].score[whatsb]/10){
            case 10:
            case 9 : fprintf(fp,"%d,%s\n",data[i].num,"A+"); break;
            case 8 : fprintf(fp,"%d,%s\n",data[i].num,"A"); break;
            case 7 : fprintf(fp,"%d,%s\n",data[i].num,"B"); break;
            case 6 : fprintf(fp,"%d,%s\n",data[i].num,"C"); break;
            default :fprintf(fp,"%d,%s\n",data[i].num,"F"); 
        }
    }
    fclose(fp);
    return 0;
}

 ```




~~なんだこの糞コード！？たまげたなぁ~~

以下解説

###とりあえず構造体作るか　


```c
typedef struct{
    int num;
    int score[5];
}student;
```

各生徒の学生番号と成績を入れる箱を作りました
構造体でいろいろすると言っても複雑な処理はいりません、

```c
student data[Students];
```


これで"構造体の配列"の完成です、
student型の配列の2番目のscoreの1つ目はdata[1].score[0]で表せます、簡単ですね


###　毎回保存する動作書くの冗長だから関数化してループさせるか

```c
char savefile[][18] = {"grade_Eng.csv","grade_Math.csv","grade_Japa.csv","grade_Sci.csv","grade_Civ.csv"};
(中略)
for(i=0;i<5;i++){
    if(Dealer(savefile[i],i,data)==-1)break;
}
```

書き出す科目のファイル名と科目の番号、生徒のデータを引数に持ったDealerという関数を作っておいて、そこにfor文で各科目を入れていきます
科目の番号ですが1番目は英語、2番目は数学ですね
あとはDealer記述して終わりです

```c
int Dealer(char *filename,int whatsb,student data[]){
    int i;
    if( (fp = fopen( filename, "w" )) == NULL)return -1;
    for(i=0;i<Students;i++){
        if(data[i].score[whatsb]<0 || 100 < data[i].score[whatsb])fprintf(fp,"%d,%s\n",data[i].num,"X");
            switch(data[i].score[whatsb]/10){
            case 10:
            case 9 : fprintf(fp,"%d,%s\n",data[i].num,"A+"); break;
            case 8 : fprintf(fp,"%d,%s\n",data[i].num,"A"); break;
            case 7 : fprintf(fp,"%d,%s\n",data[i].num,"B"); break;
            case 6 : fprintf(fp,"%d,%s\n",data[i].num,"C"); break;
            default :fprintf(fp,"%d,%s\n",data[i].num,"F"); 
        }
    }
    fclose(fp);
    return 0;
}
```

switch文でなかなか奇麗に書き表せます、考えた人すごい(小並感)


### まとめ

つかれた



### 追記(1月28日更新)

```
fscanf( fp, "%d,%d,%d,%d,%d,%d\n",&data[i],&data[i].score[0],&data[i].score[1],&data[i].score[2],&data[i].score[3],&data[i].score[4]);
```

を

```
fscanf( fp, "%d,%d,%d,%d,%d,%d\n",&data[i].num,&data[i].score[0],&data[i].score[1],&data[i].score[2],&data[i].score[3],&data[i].score[4]);
```

に変更、あと100点だった時にFが出力されていたのでcase 10:を足して修正
一応コンパイラも通っていて正しい出力までできていたのでふぅむ……といったところ
構造体配列のメモリ確保がどうなってるのか少し垣間見れた気がします