第8回:配列とファイル (11/12)


第7回演習:解答例


配列とファイル

今回は,前回のファイルの復習と,「ファイルからデータを配列に読み込む」,「配列データをファイルへ書き出す」手順を学ぶ.

前回のプログラムでは,ファイルからデータを一個取り出したり書き込んだりを行いました.
では,ファイルからすべてのデータを配列にすべて読み込んで,その後,画面に表示するにはどうしたら良いか.

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


#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 siny[10];
    FILE *fp;

    fp = fopen("sincos.csv", "r");     /*  読み込みモードでファイルをオープン  */
    if(fp == NULL) {
        printf("ファイルを開くことが出来ませんでした.¥n");
        return;
    }

    for(i=0; i<10; i++){
        fscanf(fp, "%f", &(siny[i]) );     /*  1行読む  */
    }

    fclose(fp);

    for(i=0; i<10; i++) {
        printf("%f¥n", siny[i]);
    }
}

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

ファイルの終わりには,文字列と同様,ファイル終端を表す特殊なマーク「EOF」がついている.(EOFは,End Of File の略)

ファイルを先頭から順に読み込んでゆき,終わりに達したかどうかを判定する(=EOFを探す)には,feof()関数を使う.
この関数はファイルの終わりに達すると「真」(正確にはゼロでない値)になる.

これを使ってデータの並んだファイルから配列にデータを読み込んでみよう.

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


#include <stdio.h>

void main()
{
    int i, n;
    float siny[512];    /* 大きめのサイズの配列を用意しておく. */

    FILE *fp;

    fp = fopen("sincos.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(100点満点で正の整数)を読み込んで,

  1. 平均値
  2. 標準偏差

を求めるプログラムを作成せよ.データ数はEOFを元に判断すること.
標準偏差などの求め方は, 前期:配列と繰り返しを参考にすること


(2)更に,平均値,標準偏差から各点数の偏差値を求め,ファイルに保存するプログラムを作成せよ.


(3)ファイルから4×4の2次元行列Aを読み込み画面に表示するプログラムを,以下を参考に関数を用いて作成せよ.
行列は、次のファイルを(右クリック-->[対象をファイルに保存])で作成したプログラムと同じフォルダに入れること.
   [Amat.txt],


#include <stdio.h>

/*4×4の行列をファイルから読み込む関数*/
void read_matrix(char filename[], float mat[4][4])
{
	int i,j;
	FILE* fp;
	
	………
}

/*4×4の行列を表示する関数*/
void print_matrix(float mat[4][4])
{
	………
}

/*メイン関数*/
void main()
{
	float Amat[4][4];
	char filename1[]="………";
	
	read_matrix(…,…);
	
	print_matrix(…);

}

(4)ファイルから4×4の2次元行列A,Bを読み込み行列の乗算A・B=Cを行い、計算結果Cをファイルに出力するプログラムを作成せよ.
行列Aと同様にBも保存する.[Bmat.txt],

行列の乗算:

行列B,Cは以下の形になる.


#include <stdio.h>

/*4×4の行列をファイルから読み込む関数*/
void read_matrix(char filename[], float mat[4][4])
{
	int i,j;
	FILE* fp;
	
	………
}

/*4×4の行列をファイルに書き出す関数*/
void write_matrix(char filename[], float mat[4][4])
{
	int i,j;
	FILE* fp;
	
	………
}

/*4×4の行列を表示する関数*/
void print_matrix(float mat[4][4])
{
	………
}

/*行列の掛け算を行う関数*/
void multi_matrix(float Amat[4][4], float Bmat[4][4], float Cmat[4][4]) 
{
	int i,j,k;
	
	for(…;…;…){
		for(…;…;…){
			for(…;…;…){
				………
			}
		}
	}

}

/*メイン関数*/
void main()
{
	float Amat[4][4], Bmat[4][4], Cmat[4][4];
	char filename1[]="………";
	char filename2[]="………";
	char filename3[]="………";
	
	read_matrix(…,…);		/*同じ作業は関数化するほうが使いやすいプログラムになる*/
	read_matrix(…,…);		/*行列の読み込みプログラムの呼び出し*/
	
	print_matrix(…);			/*行列の表示プログラムの呼び出し*/
	print_matrix(…);
	
	multi_matrix(…,…,…);	/*行列の掛け算プログラムの呼び出し*/
	
	print_matrix(…);
	
	write_matrix(…,…);		/*行列の書き込みプログラムの呼び出し*/

}

(5)前回の課題(4)の文字列の長さを計算する関数を用いて、文字列の前後を反転させる関数を作成せよ.


#include <stdio.h>

/*文字の長さを数える関数*/
int moji_nagasa(char str[])	
{
	………

}

/*文字を入れ替える関数*/
void moji_irekae(char str[], int n)
{
	………
}

/*メイン関数*/
void main()
{
	int n;
	char str[128];

	printf("文字列を入力してください:");
	scanf("%s", str);

	printf("入力された文字列は,%sです.", str);
	printf("文字数は,%dです.", n = moji_nagasa(str));
	
	moji_irekae(str,n);
	
	printf("入れ替えた文字列は,%sです.", str);

}

授業終了時までのプログラムと完成した提出用プログラムをoh-meijiシステムを使って提出すること.
授業終了時に送るのは出席の確認用であり,完成した課題は提出用の回に送ること.
(提出期限を厳守し,提出用の回に提出しないと採点を行わない)


また提出の行い方については,以下のページを参照してください.
課題の提出方法