第7回 プログラミング入門 演習

【演習の注意事項】を良く読んで解答してください


配列について(1)

【主な内容】

今日勉強した配列とこれまでに勉強した入出力文、制御文(for, ifなど)の組み合わせで、少し複雑なプログラムに挑戦しましょう。

配列を使用する基準

配列はどのような場合に使用すればよいのでしょう。
合計や平均を求めるだけの単純な計算では特にデータを保持しておく必要がありません。
一方、計算の後で
ような処理には配列を使用して値を記憶しておく必要があります。

演習課題

以下の例題と、3つのレベル (初級レベル, 中級レベル, 上級レベル)の全ての 課題に解答しなさい。各々の課題毎にファイルを作成しなさい。

今回の課題はテキスト(文書)ファイルで提出するものと C言語のプログラムファイルで提出するものがあります。 前者は".txt"、後者は".c" という拡張子をつけて下さい。 各課題にはファイル名が指定してあるので、その指示にしたがって下さい。

例題

講義資料(ハンドアウト)の例題 lec07-1.clec07-2.clec07-3.clec07-4.clec07-5.clec07-6.clec07-7.clec07-8.c のソースプログラムをコピーし、そのプログラムの動作を予測した上で、コンパイル・実行を試してみなさい。

コピーの方法:
% cd ~/Prog0/Ex07
% cp /home/course/prog0/public_html/2007/lec/source/lec07-?.c .



初級レベル

(A-1)
配列に関するプログラムの落とし穴を実験します。

ファイル名: ex07a1.txt

(1)次のプログラムをコンパイル・実行し、出力結果をex07a1.txtに書きなさい。


(2)存在しない配列要素に代入を行なうとどうなるかを確かめるため、上記のプログラムにあるfor文を次のように変更し、コンパイル・実行しなさい。出力結果が変わった原因を考え、ex07a1.txtに追加しなさい。
for(i = 0 ; i < 11 ; i++){   /* わざと 「i < 11」に */


(A-2)
次のプログラムでは、最初のループで、配列scoreに1クラス分(40人)の点数を作成しています。このプログラムに、以下の処理を追加してください。
  1. このクラスの点数の平均点を計算する(変数名:heikin)
  2. 平均点以上の点数をとった学生を合格とし、合格者を数える(変数名:n_gtavg)
補足説明
  1. 点数はキーボードから直接入力の代わりに、rand()*100/(RAND_MAX+1)+1で1〜100までの乱数を作成しています(Lec07-22参照)
ファイル名: ex07a2.c



(A-3)
整数型で要素数が10の配列を作り、それぞれの配列要素を 1、12,、23、34、45、56、67、78、89、90 で初期化し(初期化文を使用する)、キーボードから入力された整数値を添字とする配列要素を表示する プログラムを作成しなさい。

動作の要件(これを一般に仕様と呼びます):

ファイル名: ex07a3.c

[実行例]
% ./a.out
添字を入力してください 2
Data[2]=23
% ./a.out
添字を入力してください 10
範囲外です:index=10



中級レベル

(B-1)
5人分の成績の評点(0〜100)を入力し、評点と評価(A,B,C,D,F)を一覧表の形式で表示するプログラムを作成しなさい。

ファイル名: ex07b1.c

評点と評価の対応関係は以下のとおり、
動作の要件(仕様):
[実行例]
% ./a.out
5人分の評点を入力して下さい。
50
100
70
0
35
1:  50  C
2: 100  A
3:  70  B
4:   0  F
5:  35  D

ヒント:
(1)5人分の評点を入力し、配列に格納する場合、scanfを5つ書いても良いが、拡張性を考えるとscanfを1つにしてfor文で繰り返す方がなお良い。for文を使って配列に入力する方法は講義資料サンプル1(lec07-5.c)などを参照のこと。

(2)printf文を使って数値を表示する際、桁を合わせたい場合は今までの%dに代わって%3dなどのように、表示すべき数値の桁数を指定すれば良い。%3dは3桁での表示を指定する。



(B-2)
配列を利用すると「漸化式」の計算が簡単かつ高速にできる場合がある。
例えば2のi乗(i=1,...,N−1)までの各値(2のベキ乗)を表す漸化式は下記の通りである。

この漸化式は下記のようにプログラム化する事が出来る。 (但し10個の要素を持つ配列を使うためN=10−1とする)

このプログラム例に以下の処理を追加しなさい。
  1. 整数値をキーボードから入力する
  2. 入力した整数値より大きい配列要素のみを出力する

ファイル名: ex07b2.c

[実行例]
% ./a.out
1  2  4   8  16  32  64  128  256  512  ←注:配列の出力
27                                          ←注:整数の入力
32  64  128  256  512                   ←注:該当する数値出力


(B-3)
(B-2)のプログラム例を以下の出力になるように変更してください。

ファイル名: ex07b3.c

[実行例]
% ./a.out
data[1] = 2 * data[0] = 2 * 1 = 2
data[2] = 2 * data[1] = 2 * 2 = 4

  ・・・・・・

data[9] = 2 * data[8] = 2 * 256 = 512
ヒント:以下のprintf文を工夫する
for(i = 1 ; i < 10 ; i++){
  printf("  ", ...);
}



上級レベル

(C-1)
10個の整数をキーボードから配列に入力し、その中の最大値と最小値を表示するプログラムを作成しなさい。 なお、入力された整数も最後に表示すること。

ファイル名: ex07c1.c

[実行例]
% ./a.out
10個の整数を空白で区切って入力してください。
5 3 1 10 4 9 20 -5 15 -10
最大値は20です。
最小値は-10です。
入力された整数の表示
5 3 1 10 4 9 20 -5 15 -10
ヒント:配列a[10]から最大値を探す方法

最大値を保持する変数(例えばmax)に最初の要素a[0]を代入
for(), while()などで,a[i] (i = 1,...,9)に対し,以下の処理を行う
  もしa[i]がmaxより大きければ,maxにa[i]を代入

上記処理の結果,maxにはa[10]中の最大値が残る


(C-2)
下記プログラムは要素の入れ替えにより配列を逆順にしようとしている。即ち
   最初の要素←→最後の要素    (←→ 入れ替えの意味)
   2番目の要素←→後ろから2番目の要素
   3番目の要素←→後ろから3番目の要素
       ・・・・・・
期待している結果は次の通り。

[実行例]
% ./a.out
1   2   4   8  16  32  64 128  256  512   ←注:入れ替え前
512 256 128  64  32  16   8   4    2    1   ←注:入れ替え後      
しかし,下記プログラムの入れ替え処理には問題がある(コンパイル/実行をすると分かる)。 プログラムを理解し、入れ替えを正しく行うように書き直しなさい。

ファイル名: ex07c2.c

ヒント: 二つの要素値を入れ替えるには,値の一時保存用変数が必要です。



(C-3)
任意の整数v(v>0)は2のベキ乗の組み合せで表現できる。例えば整数13は以下のように分解できる。
13 = 8+4+1 = 2+ 2+ 2
(B-2)のプログラム例(演習の解答ではなく)では2の9乗までの値が配列として作成されている。 この(B-2)のプログラム例に以下の処理を追加しなさい。
  1. 整数(0〜511の値)をキーボードから入力する
  2. 入力された数を、上の2のベキ乗配列を用いて分解し、その結果を出力する
ファイル名: ex07c3.c

[実行例1]
% ./a.out                         
1  2  4   8  16  32  64  128  256  512  ←注:2のベキ乗配列の出力
13                           ←注:入力
13 >> 8  4  1                     ←注:←分解処理の結果
[実行例2]
% ./a.out                         
1  2  4   8  16  32  64  128  256  512   
511                               
511 >> 256  128  64  32  16  8  4  2  1      
[実行例3]
% ./a.out                         
1  2  4   8  16  32  64  128  256  512   
16                                
16 >> 16                                    
ヒント:
キー入力された値が変数vに入っているとする
  1. vが配列のどの数字の間に入っているかを、配列の後ろから「比較」
  2. あるiに対し (data[i] > v) かつ (data[i-1] <= v)であれば、 data[i-1]をvから分解した値として「出力」
  3. vからdata[i-1]を引く
  4. 新しいvに対して上記の「比較」と「出力」を継続




何か疑問や間違いがあれば以下に連絡して下さい。
プログラミング入門演習問題担当(prog0)