2 配列の応用

2.1 ファイルのデータを配列に格納

配列を応用したプログラムの練習を行う.2003年11月の秋田市の毎日の1時間毎の気温の データファイルがある.それから,日々と11月の最高気温を表示するプログラムを作成す る.

気温は,表1のようなになっている.この気温の部分のみがファイル (/tmp/1e/temperature.txt)に書かれており,そのフォーマット(書式)は次の ようになっている. -4pt


表 1: 11月の気温
  0時 1時 2時 3時 4時 5時 $ \cdots$ 23時
1日 8.4 8.0 7.3 6.5 6.0 6.1 $ \cdots$ 10.8
2日 11.4 11.6 11.3 10.8 10.4 9.5 $ \cdots$ 15.8
3日 15.9 15.8 15.2 14.9 14.5 14.3 $ \cdots$ 15.8
$ \vdots$ $ \vdots$ $ \vdots$ $ \vdots$ $ \vdots$ $ \vdots$ $ \vdots$ $ \ddots$ $ \vdots$
30日 13.9 13.7 13.9 13.8 13.6 14.7 $ \cdots$ 11.2

次のようにすれば,emacsで温度のデータが書かれているファイルの中身を見ることができる.
	
	emacs /tmp/1e/temperature.txt

このファイルの気温を読み込んで,日々とその月の最高温度を表示するプログラムの例を リスト1に示す.ここではij時のデータを二次元 配列temp[i][j]に格納している.二次元配列については先週述べたので,ここでは 詳しく説明しない.

ファイルからデータを読み出すプログラムは,まだ学習していない.2年生のはじめに学習する ことになっているが,簡単に述べておく.ファイルからデータを読み出すために は,(1)ファイル情報を格納する変数の用意,(2)ファイルのオープン,(3)データの読み 込み,(4)ファイルのクローズ--という一連の動作を行う.実際には,リスト 1のとおりで,ファイル操作に関する部分を以下に示す.


   1 #include <stdio.h>
   2 
   3 int main(void){
   4   FILE *fp;
   5   double temp[31][24];
   6   double max_day[31];
   7   double max_nov;
   8   int dates, hours;
   9   int i, j;
  10 
  11   dates = 30;                                // 日数と時間の設定
  12   hours = 24;
  13 
  14   fp=fopen("/tmp/1e/temperature.txt","r");   // ファイルをオープン
  15 
  16   for(i=1; i<=dates; i++){                   // ファイルからデータを読む
  17     for(j=0; j<=hours-1; j++){
  18       fscanf(fp, "%lf", &temp[i][j]);
  19     }	
  20   }
  21 
  22   fclose(fp);                                // ファイルをクローズ
  23   
  24   /* --------------- 最大と最小、平均の計算 --------------------*/
  25 
  26   max_nov = temp[1][0];             // 11月の仮の最高気温 1日の0時
  27 
  28   // ---------- i日のループ -----------------------------
  29   for(i=1; i<=dates; i++){          // iは、日にちを表す
  30     max_day[i] = temp[i][0];        // i日の仮の最高気温 i日の0時
  31 
  32     // ---------- j時のループ -----------------------------
  33     for(j=0; j<=hours-1; j++){      // iは時刻を表す    
  34 
  35       if(temp[i][j] > max_day[i]){  // i日の最大気温の探索
  36 	max_day[i] = temp[i][j];
  37       }
  38       
  39     }   // ----------j時のループの終わり --------------
  40     
  41     if(max_day[i] > max_nov){       // 11月の最大気温の探索
  42       max_nov = max_day[i];
  43     }
  44     
  45   }   // ----------i日のループの終わり --------------
  46 
  47 
  48   printf("\n\nTemperature  November/2003 at Akita\n"); 	
  49   printf("------------------------------------\n");
  50   printf(" day\tmax\n");
  51   printf("====================================\n");
  52   
  53   for(i=1; i<=dates; i++){
  54     printf("%3d\t%5.1lf\n",i, max_day[i]);
  55   }
  56 
  57   printf("------------------------------------\n\n"); 
  58 
  59  
  60   printf("max(Nov.)     = %5.1lf\n", max_nov);
  61   
  62   return 0;	
  63   
  64 }


\fbox{実行結果}
Temperature  November/2003 at Akita
------------------------------------
 day    max
====================================
  1      20.3
  2      20.4
  3      22.8
  4      14.9
  5      18.4
  :         :
  :         :
 29      15.7
 30      15.1
------------------------------------

max(Nov.)     =  22.8

2.2 配列を関数に渡す

配列を関数に渡す方法を学習する.これはちょっと難しいので概略のみを説明する.本当 は,後で学習するポインターと併せて理解すべき内容である.ここでは,配列のデータを 関数にまたがって受け渡せす方法が分かれば良い.以降,具体例をもって説明する.

10人の英語の成績を処理するプログラムを考える.このプログラムは,次のような動作を する. -4pt

このプログラムのでは,メイン関数とユーザー定義関数diff_ave()で,同じ配列を 使用している.最初,配列seiseki[]には英語のテストの点数が格納されており,最 後には各人の平均値からの差が格納されている.実引数と仮引数のデータの渡す方法が普 通の変数と配列では異なる. -4pt

配列を引数に使うと,実引数と仮引数が同じメモリーを使う理由は,処理時間を短くする ためである--と言われている.通常,配列に格納されたデータは非常に大きく,関数を 呼び出すたびに実引数の配列を仮引数の配列にコピーすると膨大な時間がかかり,計算コ ストの増大につながる.

また,仮引数の書き方も変わっている.仮引数の配列はdata[]のようにして,配列 のサイズは不要である.二次元や三次元の仮引数の場合,fuga[][100]hoge[][200][300]のように,左端の配列のサイズを書かない.なぜ,このような変なこと をするか?.これについては,ポインターを学習しないと理解できないので,ここでは説 明しない.

   1 #include <stdio.h>
   2 
   3 int diff_ave(int n, int data[]);
   4 
   5 /*==============================================================*/
   6 /*   main function                                              */
   7 /*==============================================================*/
   8 int main(void)
   9 {
  10   int seiseki[10], average, i, n;
  11 
  12   n=10;                          // 学生数
  13   
  14   for(i=0; i<n; i++){
  15     printf("%d番の成績\t", i);
  16     scanf("%d",&seiseki[i]);
  17   }
  18   
  19   average=diff_ave(n, seiseki);    // 関数呼び出し
  20 
  21   printf("平均点 = %d\n", average);
  22   printf("平均点との差\n");
  23   
  24   for(i=0; i<10; i++){
  25     printf("%d番\t%d点\n", i, seiseki[i]);
  26   }
  27   
  28   return 0;
  29 }
  30 
  31 /*==============================================================*/
  32 /*   平気値とその差の計算                                          */
  33 /*==============================================================*/
  34 int diff_ave(int n, int data[])
  35 {
  36   int i, sum=0, ave;
  37 
  38   for(i=0; i<n; i++){         // 点数の合計の計算
  39     sum += data[i];
  40   }
  41   ave = sum/n;                // 平均値の計算
  42   
  43   for(i=0; i<n; i++){         // 平均値との差の計算
  44     data[i] = data[i] - ave;
  45   }
  46   
  47   return ave;
  48 }

ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成18年12月22日


no counter