第7回演習の解答例

ファイルの取り扱いの基本を確認しましょう。

0.ファイルポインタの定義
1.ファイルを開く(オープンと言う)
2.ファイルから情報を変数に読み込む,またはファイルに変数の内容を書き出す
3.ファイルを閉じる(クローズと言う)

である。

ファイル入出力


(1)キーボードから入力した数値をファイルに保存するプログラムを作成せよ。

#include <stdio.h>

void main()
{
    int a;
    FILE *fp;  /*  0:ファイルポインタを宣言  */

    fp = fopen("out.txt", "w");       /*  1:ファイルを書き込みモードで開く(オープン)  */

    printf("数値を入力してください : ");
    scanf("%d", &a);

    fprintf(fp, "%d ¥n", a);           /*  2:ファイルに整数を書き込む  */

    fclose(fp);                      /*  3:ファイルを閉じる(クローズ)  */
}

(2)上問で作ったファイルに保存された数値を読み込み,画面に表示するプログラムを作成せよ。

#include <stdio.h>

void main()
{
    int a;
    FILE *fp;  /*  0:ファイルポインタを宣言  */

    fp = fopen("out.txt", "r");       /*  1:ファイルを書き込みモードで開く(オープン)  */

    fscanf(fp, "%d", &a);           /*  2:ファイルから整数を読み出す  */

    fclose(fp);                      /*  3:ファイルを閉じる(クローズ)  */

    printf("ファイルに書き込まれた数値は,%d です¥n", a);
}

(3)角度を0度から360度まで1度ずつ変えたときの,sinの値を各行に出力するプログラムを作成せよ。計算上,円周率はpi=3.141とする。ファイル名は,"sin.csv"としよう.ファイル名の末尾に .csv (拡張子と呼ぶ)をつけると,Excelで簡単に開くことができる。

sin関数の使い方は,以下のプログラムを参考にすること


#include <stdio.h>   /*printfなどの命令を使うためのファイルの読み込み*/
#include <math.h>    /*sin関数など数学用の関数を使うためには必ず読み込むこと*/

void main()
{
    int i;
    double rad,pi;	 /*sin(double x)のため,変数xはdouble型で定義すること*/
    FILE *fp;       /* 定義は,最初! */

    pi=3.141;			/*πの定義*/

    fp = fopen("sin.csv", "w");  /* ファイルを書き込みモードで開く */

    for(i=0; i<=360; i++){
        rad = i/180.0*pi;	/*ラジアン[rad]に*/
        fprintf(fp, "%f¥n", sin(rad));
    }

    fclose(fp);
}

 

第8回:ファイルと配列・関数 (6/22)


今週は,ファイルと配列・関数と組み合わせます。これまで習った知識を総動員します。どこでわからなくなっているのか,きちんと特定して,もう一度復習しましょう。

キーワード:「EOF」


配列とファイル

前回のプログラムでは,ファイルからデータを一個取り出したり書き込んだり,連続データの書き出しを行った。
今回は,ファイルから連続したデータを配列にすべて読み込もう。

配列にキーボードからデータを10個読み込むには,


#include <stdio.h>
 
void main()
{
    int i, n;
    int data[10];
 
    for(i = 0; i < 10; i++) {
        printf("%d番目のデータ:", i+1);
        scanf("%d", &(data[i]) );
    }
 
    /*  画面に表示  */
    for(i=0; i<10; i++) {
        printf("%d¥n", data[i]);
    }
}

のような手順である。これをもとに,ファイルから数値を10個,配列に読み込むように改良してみよう。ファイルには,値が一行に一つだけあるとすると,


#include <stdio.h>
 
void main()
{
    int i, n;
    float sin[10];
    FILE *fp;
 
    fp = fopen("sin.csv", "r");     /*  読み込みモードでファイルをオープン  */
    if(fp == NULL) {
        printf("ファイルを開くことが出来ませんでした.¥n");
        return;
    }
 
    for(i=0; i<10; i++){
        fscanf(fp, "%f", &(sin[i]) );     /*  1行読む,ファイルのデータの並びにあわせる  */
    }
 
    fclose(fp);
 
    for(i=0; i<10; i++) {
        printf("%f¥n", sin[i]);
    }
}

ここで,事前にファイル中のデータ個数がわからない場合はどうしたらよいだろう?

ファイルの終わりには,文字列と同様,ファイル終端を表す特殊なマークEOFがついている。(EOFは,End Of File の略)。ファイルを先頭から順に読み込んでゆき,終わりに達したかどうかを判定する(=EOFを探す)には,feof()関数を使う。この関数はファイルの終わりに達すると「真」(正確にはゼロでない値)になる。これを使ってデータの並んだファイルから配列にデータを読み込んでみよう。

配列のサイズは,あらかじめ読み込むデータより大きめに用意しておく。


#include <stdio.h>
 
void main()
{
    int i, n;
    float siny[512];    /* 大きめのサイズの配列を用意しておく. */
 
    FILE *fp;
 
    fp = fopen("sin.csv", "r");
    if(fp == NULL) {
        printf("ファイルを開くことが出来ませんでした.¥n");
        return;
    }
 
    n = 0;
 
    /*  ファイルが終わりでない 「かつ」 配列を飛び出さないうちは,読み込みを続ける  */
    while ( ! feof(fp) && n < 512) {
        fscanf(fp, "%f", &(siny[n]));
        n++;
    }
 
    fclose(fp);
 
    n = n-1; /* 上のwhileループでは,EOFの行を余分に読み込んでいるので,実際のデータ数は一つ少ない. */
 
    /*  画面に表示  */
    for(i=0; i<n; i++) {
        printf("%f¥n", siny[i]);
    }
}

演習課題

(1)試験結果のデータファイルtestdata.txt(右クリック-->[対象をファイルに保存] )を読み込んで,大きい順に並べ替え,別のファイルに出力するプログラムを,第6回(3)を元にして作成せよ。

(ステップ1)関数を用意しないで,main関数だけで作成してみる。

(ステップ2)ファイルからのデータ読み込み,書き出し,並べ替えを下記のように関数にし,main関数をすっきりさせる。


#include <stdio.h>

/*ファイル入力の関数 ファイル名と配列のアドレスを受取,データの読み取り個数を戻す*/
_____ load(_____)	
{
	 ****** 
}

/*並べ替えの関数*/
_____ sort(_____)
{
	 ****** 
}

/*ファイル出力の関数*/
_____ store(_____)	
{
	 ****** 
}

/*メイン関数*/
void main()
{
    int data[256];  /* データ用配列 */
    int n;         /* データ数 */

    n = load("testdata.txt", data);  /* ファイルからデータを配列に読み取り,データ数を戻す */  
    sort(data, n);   /* 配列を並べ替える */
    store("result.txt", data, n);  /* 結果を保存する */
}

(2)次に各点数に順位を付けて,csvファイルに保存するプログラムを作成せよ。

注意1:ただし,同じ点数の者が2名いたら,次の点数の者の順位は,一つ飛ぶ。 たとえば,47点が53位で,47点の者が2名いたとすると,46点の者は,55位となる。
注意2:結果についてはデータと順位両方をファイルに書き込む。 csvファイルに書き込む時,fprintf関数における値の型を書く所をカンマ区切りすることによってセルの列を区別することができる。

CSVファイルの中身の例:

100,1
99,2
98,3
98,3
97,5

....

(3)挑戦! できる人は,各点数の偏差値を求めなさい。