模擬テスト(2018年度中間テスト問題)

諸注意

  • 各問題に対して,それぞれソースコード(.cppファイル)を作成すること.
  • 提出は,毎回の演習と同様,zip形式でまとめて提出すること.
  • インデントが正しくないと大幅減点となるので注意すること.



問題


    1. 以下のように,桁を揃えた九九のテーブルを表示せよ. ただし,奇数行のみ表示しなさい. 繰り返し文の二重ループを必ず使用すること.
      実行例
      
      

      解答例


      解説

      • まずは通常の九九テーブル作成から始めよう.奇数行だけの表示にするのは最後にやればいいです.
      • 二重ループにするとき,行と列はどちらが先になるか,よく考えよう. それがわかれば奇数行だけにするのはどこを変更すればよいのか(7行目の終わりのほう)すぐにわかるはず.
      • 表示したいのは九九ですから,縦☓横ですね(9行目).桁を揃えるためのフォーマット記述子の桁指定に注意
      • 一行分の表示が終わったら,改行しよう(11行目).これでテーブル状になります.




    2. n個の実数が収められた配列を引数にとり, その中の最大値を返す 関数 find_max を作成しなさい.
      この関数を用いて, キーボードから入力された5個の実数の最大値を 表示するプログラムを作成せよ.

      • 注1:入力されたn個のデータは必ず配列に格納し, この配列とデータの個数の情報を関数 find_max に渡すこと.
        また,画面表示はmain関数内のみで行うこと.
      • 注2:nの最大値は100とする.今回は100を超えたときのエラー処理は考えなくて良い.

      
      ???? find_max(...)
      {
      	/* 任意のデータ個数に対応できる関数とすること */
      	/* この関数の中で画面に表示してはならない */
      	....
      	return ???; // 配列の中の最大値を見つけて返す
      }
      
      int main(void)
      {
      	const int N = 100;  /* 最大のデータ個数 */
      	const int K = 5;	/* キーボードから入力するデータ個数 */
      	/* ここで配列の宣言をする */
      
      	/* ここでfind_max関数を呼ぶ */
      
      	/* ここで結果を表示する */
      
      	return 0;
      }
      

      解答例


      解説

      • 配列の「実体」を宣言しているのはmainの中,28行目です.それ以外の場所では 配列の宣言はしていません.つまり,このプログラムの中には,配列はこのひとつしかありません. この「実体」の先頭アドレスを引数で各関数に渡しているだけです.配列が存在する「場所」を教えてあげている,ということです.
      • 配列の容量は,実際に使用するよりも大きくなければなりません.この例では,100個の容量を 確保して,実際に使用しているのは先頭から5個だけです. 容量の方が小さくなってしまって,「欄外」にデータを書き込んだりすると, 「飛行機の墜落(くらいの重大な事故)」が起こってしまいます.
      • 配列を引数で渡すとき,データが何個入っているのかはわかりません. (配列の先頭の場所を教えてあげているだけですから) ですので,データの個数を 別途教えてあげる必要があります.この例では,引数の int n がそれに当たります(4, 15, 30, 31行目).
      • find_max関数の中では,maxという「一時的な最大値」を格納する変数を用意します. 引数で渡されてきた配列をスキャンして,maxより大きな値が見つかったらmaxを書き換える, ということをしています.すべてのスキャンが終わったときには maxは一時的ではなく, すべてのデータの中での本当の最大値になっているというわけです.
      • key_in()は関数にしなくても構いませんが, main()の中がゴチャゴチャになりすぎないようにするためにこの様にしています.




    3. 下記のように,文章内の単語の先頭の文字をすべて大文字に変換して表示せよ. main関数は以下の通りとし,変更しないこと.

      実行例:
      変換前:Hello! I am a computer.
      変換後:Hello! I Am A Computer.
      

      コード例:
      
      void capitalize(...)
      {
      	....
      }
      
      int main(void)
      {
      	char str[] = "Hello! I am a computer.";  /* どのような文章にも対応できるように */
      
      	printf("変換前:%s\n", str);
      	capitalize(str);
      	printf("変換後:%s\n", str);
      
      	return 0;
      }
      

      解答例


      解説

      • このプログラムの核心部分は,20-22行目あたりです. 小文字 str[i]の左隣の文字 str[i-1] がスペースであるとき, 小文字始まりの単語の先頭だと認識して(21行目), 大文字に変換しています(22行目)
      • ここで,文字がスペースなのか,小文字なのかの検査をそれぞれ別の関数(4, 8行目の関数)に追い出しています. この様にすることで,if文(21行目)がごちゃごちゃせず,とても見やすいものになっています.
      • この様に,「小さな単機能の関数」を上手に作ることが,良い (=バグが入りにくい,=バグを見つけやすい)プログラムを作る秘訣です.
      • プログラム中に「数字」を直接書いてはいけません.例えば,5, 9, 13行目には,それぞれ,'a'や’A'を 使っています.これを文字コード 0x61などと書いてしまうと後に見たとき,この数字が何を示しているのかわかりにくくなり, 理解が難しい,デバッグが難しいプログラムになってしまいます.
      • その一方で,str[0]などの記述(17,18行目など)は,明らかに「文字列の先頭」を意味していることがわかるので, この 0 は使っても何ら問題ないと思います.




    4. キーボードから 2 より大きい整数 n を入力すると,2 から n までの間の素数を以下のように表示したうえで,それらの和を表示せよ.
      n が 2 より大きい数でない場合はエラーメッセージを表示して,正しい値が入力されるまで,繰り返し再入力させるようにせよ.
      (整数が入力されると仮定して良い.)
      実行例:
      
      2より大きい整数を入力:2
      入力エラー!
      
      2より大きい整数を入力:-2
      入力エラー!
      
      2より大きい整数を入力:10
      
      2から10までの素数の和は
      2 + 3 + 5 + 7 =	17
      です.
      

      解答例


      解説

      • 素数はべた書きしたりせず,計算して求めよう!
      • 素数の定義は,「それ自身と1以外では割り切れない自然数」なので,それをそのままプログラムコードにします. 具体的には,2〜n-1までの数で実際に割ってみて,割り切れない(剰余が0にならない)ことを確認すれば良いです.
      • 8行目は,従って,
        for(int i=2; i<x; i++){
        でもOKです.
      • ここでは,isprime()の戻り値にその素数自体を返していますが,単にTrue(=1)を返すので構いません.その場合, int p(36行目)はなくなり,37行目もpではなく,iを使えばOKです.




    5. 1∼100までの値を画面に表示しなさい.
      この際,4 の倍数と 4 が付く数字のときだけ [カッコ] 書きで表示すること.
      実行例:
      1 2 3 [4] 5 6 7 [8] 9 10 11 [12] 13 [14] ... 39 [40] [41] [42] ... [49] 50 51 [52] ... 99 [100]
      

      解答例


      解説

      • 問題では「4」と限定していますが,解答例では変数(base や n)を用いて どのような値にも対応できるプログラムにしています.
      • このプログラムも肝心な部分は24行目のあたりです.「ある数の倍数」と「ある数が含まれるか」 という検査を行い,OR(=どちらか一方でもOK)で結んでいます.
      • 例によって,それぞれの判定をそれぞれの関数に追い出して見やすくしています.
      • 倍数であるかどうかは,割り切れるかどうか,で判定できます(5行目).
      • 含まれるかどうか,は短いですが少し複雑です.
        • まず,いちばん下の一桁目から,一桁ずつ検査していきます.(11行目)
        • 1の位だけに注目するには,10で割った余りを計算します.当然それは0-9の数字になりますね!
        • ここに「4が含まれるか」は単に「4であるかどうか」を調べれば良いですね.
        • 含まれればすぐにTrueを返してしまいます.一つ見つければ十分なので.(ここまで11行目)
        • これで1桁目の検査がおわりました.4が含まれていない場合は一つ上の桁を検査します(12行目)
        • そのためには全体を10で割ってしまえば,上の桁が一つ下に下がってきますね!
        • これを繰り返せばOKですが,繰り返していって桁がなくなると,割った値が0になるので, これをループの終了判定にします(10行目).


以上