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

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


関数(2)

【主な内容】

前回学んだ関数の概念を使いこなすためにいろいろな例題をやりましょう。

演習課題

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

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

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

コピーの方法:
% cd ~/Prog0/Ex11
% cp /home/course/prog0/public_html/2007/lec/source/lec11-*.c .


初級レベル

(A-1)
関数における変数の値

以下のプログラムでは関数print_value( m, n )を利用して出力の順番mと変数の値nを出力させています。 このプログラムを実行すると、以下の出力結果のような形式で表示されます。 まず、プログラムを実行せずに出力結果の?の部分を予想し、その結果をファイルに保存しなさい。 その後、実際に実行した場合の出力結果をそのファイルに追加して下さい。 その際、予想したものと実際に実行したものの区別がつくようにファイルを作成すること。 また、予想をする際は出力順で記載すること。

ファイル名: ex11a1.txt

(ヒント)同一の名前である変数n のそれぞれの出力値がどの関数(mainも含む)から呼ばれているのか、また何故その値になるのかを、じっくり考えてみてください。

[サンプルプログラム]
#include <stdio.h>

int function1 ( int );
int function2 ( int );
void print_value (int, int );

main()
{
  int n = 3;

  print_value( 0, n ); 
  function1( n );
  print_value( 1, n ); 
  function2 ( n );
  print_value( 2, n ); 
}

int function1( int n ) 
{
  print_value( 3, n ); 
  n = n * n;
  print_value( 4, n ); 
  return n;
}

int function2 ( int m )
{
  int n=0;

  print_value( 5, n ); 
  n = m * m;
  print_value( 6, n );
  return n;
}

void print_value (int m, int n ) 
{
  printf("No.%d, n:%d\n", m, n ); 
}
[出力結果]
No.?, n:?
No.?, n:?
No.?, n:?
No.?, n:?
No.?, n:?
No.?, n:?
No.?, n:?




(A-2)
関数の使用例

以下のプログラムは、一次関数y=ax+bを利用し、まず入力されたa,bより一次関数の式を表示した後、xを入力し、最終的にyを計算し表示します。 ただし、a,b,x,yは全て実数とし、ax+bの計算処理部は関数functionとして作成されています。
このプログラムの下線部を埋めて完成させなさい。

ファイル名:ex11a2.c

#include <stdio.h>

_______ function (_______________);

main()
{
  float a,b,x,y;

  printf("二つの実数a, bを入力してください: ");
  scanf("%f %f", &a, &b);
  printf("関数はy=%5.2f x+%5.2f です。\n",a,b);
  printf("では、実数xを入力してください: ");
  scanf("%f",&x);
  y=function(_______________);
  printf("y = %5.2f \n", y);
}
_______ function(______________)
{  
  return a*x+b;
}




(A-3)
自動変数

次のプログラムをコンパイル・実行し、その出力結果を書きなさい。そして、何故このような結果になったのか「自動変数の適用範囲」の観点から 説明しなさい。

ファイル名:ex11a3.txt
#include <stdio.h>

void print_ij(void);

main()
{
  int i = 1, j = 6;

  printf("main: i = %d, j = %d\n", i, j);
  print_ij();
  printf("main: i = %d, j = %d\n", i, j);
}

void print_ij(void)
{
  int i = 3, j = 8;
  printf("func: i = %d, j = %d\n", i, j);
}





中級レベル

(B-1)
関数の使用例

1からnまでを加算する関数sum(int)を作成し、それを利用して、nを入力し、加算結果Sを出力するプログラムを作成しなさい。ただし、n, Sは整数型とします。
S=1+2+3+.......+n

ファイル名:ex11b1.c

[実行例]
% ./a.out
整数nを入力してください。
7
1から7までの和は28です。




(B-2)
関数の例

直角三角形の斜辺以外の2辺の長さから斜辺の長さを求めるプログラムを作成しなさい。その際、直角三角形の斜辺以外の2辺の長さから斜辺の長さを返す関数hypotenuseを作成し、利用しなさい。引数と戻り値は共にfloat型とします。数値入力と結果出力はmainで行なって下さい。

なお、math.hをインクルードして、pow(),sqrt()を使って構いません。使い方は演習第10回(C-4)やオンラインマニュアル等を参照してください。

ファイル名: ex11b2.c

[実行例]
% ./a.out
直角三角形の斜辺以外の2辺の長さをそれぞれ空白で区切って入力してください。
3.0  4.0
斜辺の長さ = 5.000000




(B-3)
関数の例

2つの複素数の積を計算するプログラムを作成しなさい。

仕様
・値の入力、関数の呼び出し、結果の出力はmain関数で行う。
・実部を計算する関数と虚部を計算する関数(関数名: real, imaginary) を別々に作る
・実部または虚部が0の場合、その部分は表示しない(実行例を参照)。
・実部および虚部いずれも0の場合は、0を表示する。

ファイル名:ex11b3.c

[実行例]
% ./a.out

2つの複素数の実部と虚部の値をそれぞれ空白で区切って入力してください。
複素数1 = -3.0  2.0
複素数2 = 6.0  9.0
2つの複素数の積 = -36.00 - 15.00i

% ./a.out

2つの複素数の実部と虚部の値をそれぞれ空白で区切って入力してください。
複素数1 = 3.0  2.0
複素数2 = 6.0  9.0
2つの複素数の積 =  39.00i

% ./a.out

2つの複素数の実部と虚部の値をそれぞれ空白で区切って入力してください。
複素数1 = -3.0  2.0
複素数2 = 9.0  6.0
2つの複素数の積 = -39.00
注)printfの書式に%.2fを使用して、小数点以下2桁まで表示するようにしている





上級レベル

(C-1)
データをキーボードから入力するたびに、最初に入力したものから現在入力したものまでの平均値を求め、表示するプログラムを作成しなさい。

1つ前(n-1回目)までのデータの平均値が分かっているものとして、n番目の数値を追加した時の平均値を求める関数float avg(int  データ番号 n,  float  入力データ , float   (n-1)までの平均値)を作成し、利用すること。数値の入力や結果の表示は実行例を参考にmainで行なうこととし、入力された値が0の時、終了するものとします。

ファイル名: ex11c1.c

【補足】
この問題のように、最後のデータを待たずに新たに入ってくるデータがあればその都度(逐次的に)処理することをリアルタイム処理という。

[実行例]
% ./a.out
データを入力してください!
入力値1 = 3.0
平均値1 = 3.0
入力値2 = 22.0
平均値2 = 12.5
入力値3 = 14.0
平均値3 = 13.0
入力値4 = 41.0
平均値4 = 20.0
入力値5 = 0.0




(C-2)
10進数の0〜255を8ビットの符号なし2進数で表示するプログラムを作成せよ。なお、10進数を2進数へ変換し、表示する関数void d2b(int) を作成し、それをmainから呼んで実行しなさい。

ファイル名: ex11c2.c

[実行例]
% ./a.out

2進数に直したい10進数の正の整数を入れてください
負の数の場合は終了です
43
10進数表示 43 の2進数表示は、
0 0 1 0 1 0 1 1
です。

2進数に直したい10進数の正の整数を入れてください
負の数の場合は終了です
-2




(C-3)
素数かどうかを判定する関数isprimeを作成し、2から1000までの素数を10列の表として表示するプログラムを作成しなさい。なお、実行例を参考に列が揃うようにすること(ブラウザによっては、ずれて見えることがある。各列の下1桁の位置を揃うようにして欲しいということ)。

ファイル名: ex11c3.c

[実行例]
% ./a.out
     2     3     5     7    11    13    17    19    23    29
    31    37    41    43    47    53    59    61    67    71
    73    79    83    89    97   101   103   107   109   113
   127   131   137   139   149   151   157   163   167   173
   179   181   191   193   197   199   211   223   227   229
   233   239   241   251   257   263   269   271   277   281
   283   293   307   311   313   317   331   337   347   349
   353   359   367   373   379   383   389   397   401   409
   419   421   431   433   439   443   449   457   461   463
   467   479   487   491   499   503   509   521   523   541
   547   557   563   569   571   577   587   593   599   601
   607   613   617   619   631   641   643   647   653   659
   661   673   677   683   691   701   709   719   727   733
   739   743   751   757   761   769   773   787   797   809
   811   821   823   827   829   839   853   857   859   863
   877   881   883   887   907   911   919   929   937   941
   947   953   967   971   977   983   991   997





オプション問題(採点対象外)

(D-1)
(C-2)の問題を拡張し、10進数の負の整数にも対応できるようなプログラムを作成しなさい。なお、負の2進数は2の補数で表現するものとし、プログラムの終了は EOF(Control+d)を使うこと。なお、「負の2進数は2の補数で表現する」とは、コンピュータシステム概論1で既に習ったように、「正の数(n)の10進数表示を2進数表示に変換し、その各桁の0と1を反転し、1を加えると、負数(-n)の2進数表示が得られる」ことを意味します。

ファイル名: ex11d1.c(得点には関係しません)

[実行例]
% ./a.out

2進数に直したい10進数の整数を入れてください
EOF(Control+D)の場合は終了です
-43 
10進数表示 -43 の2進数表示は、
1 1 0 1 0 1 0 1
です。

2進数に直したい10進数の整数を入れてください
EOF(Control+D)の場合は終了です
^D




(D-2)
下記のような関数を作成し、キーボードから入力した整数列(空白で区切って,0で入力終了)を、小さい方から大きい順に並べるプログラムを作成しなさい。

最小値のインデックスを返す関数int  min_index(int a[], int n1, int n2)を作成し、使用しなさい。ただし、a[]は整数列を保存した配列、n1は最小値のインデックスを探すための配列の範囲の最小値、n2はその最大値を示す。

ファイル名: ex11d2.c(得点には関係しません)

[実行例]
% ./a.out

整数列(空白で区切って、0で入力終了)を入力してください!
入力整数列
2 61 5 23 7 11 29 33 21 56 12 0
並び替えた整数列
2  5  7  11  12  21  23  29  33  56  61






何か疑問や間違いがあれば以下に連絡して下さい。

プログラミング入門演習問題担当 (prog0)