情報科学演習
2015.11.30

Back to index page



  1. 本日の作業内容


  2. 前回の小テストの結果について

    小テストでは時間の制約がある関係でコンパイルエラーの答案が出やすいのですが,今回も2つ出てきました.ちゃんとコンパイルが出来ることを確認してから提出しましょう.

    コンパイルエラーの答案: b1529 b1541

    もっと悪いのは無限ループなんですが,残念ながらこちらも出てきてしまいました.もう,マイナス100満点!としたい気持ちです.

    無限ループ: b1567

    以下は問題のある解答の例です.参考にしてください.

            int i = rand() % 6 + 1;
    

    なぜにサイコロ?

            int i;
            printf("My student number: s154037\n\n");
            for(i=1;i<=14;i++){
                    int j;
                    j += 7;
                    printf("%d ",j);
            }
    

    上のものは本人は間違いに気づきにくいんですが,初期化の行われていない変数を使ってしまった悪い例です.変数 j を初期化していないのに j += 7 のように不九語宇演算子を使用して自己代入を行っていますが,教室以外では初期化していない変数の初期値は不定ですので,変な値が出てきます.注意してください.

            sum *= 7i;
    

    プログラミングは数学とは違うので,7i のような表現は使用できませんし,変数名にも使えません.

            for(i=1; i<=100; i++){
                    if(i%7==0)
                            printf("%d\n");
            }
    

    ループは14回回せば良いだけなのに,これでは100回回っています.資源の無駄ですね.また,if 文も使用しない方が処理が高速になります.そういったことはアルゴリズム論をやれば学習するのですが,残念ながら本学科ではやりません.すみません.

    インデントの悪いものは例によって大量に出てきています.注意してください.

    インデントの不備: b1504 b1506 b1507 b1513 b1519 b1520 b1526 b1532 b1539 b1542 b1553 b1557 b1561 b1568 b1571 b1575 b1577 b1578 b1417 b1435 b1020 b1209 b1288

    解答用紙を使用しない場合も採点対象外ですので注意してください.

    解答用紙不使用: b1523

  3. 宿題の結果について

    宿題の方もいくつか問題のある答案が出ていました.また,明らかに要求しているものと違う結果を表示するようなものも提出されていました.もう少し注意しましょう.特に多かったのが,%表記に関するもので,%6d のような桁数を指定して数値を表示する方法を忘れていたものです.これは今後も使用しますのでよく覚えておいてください.

                    int i = rand() % 900000 + 100000;
                    int j = rand() % 90 + 10;
    

    原点まではしていませんが,変数名の i j などはこのような用途には使用しないように授業中に注意したはずです.以後は気を付けましょう.

            for(i=1;i<=6;i++){
                    printf("%6d / %d = %d\n",a,b,a/b);
                    a/=b;
            }
    

    このように for 文の反復の回数をあらかじめ決め打ちしているものもいくつか見られました.今回のようないつ終わるかわからないものは本来は while ループが敵しているのですが,解答例にあるように for 文でも実現できますので,覚えておいてください.

    まだ,インデントの不備が少し残っています.注意しましょう.

    インデントの不備: b1501 b1513 b1526 b1548 b1551 b1558 b1564 b1570 b1574 b1406 b1417 b1470 b1217 b1288

    解答用紙に名前が無いもの: b1507 b1470

    学生番号の出力が無いもの:b1217

  4. 前回の復習

    • 「式1」の意味

      教科書のp.39にある for 文の基本形式ですが,その内のまず「式1」 についてもう少し説明しておきます.良くあるのが,i=1 のようなも のですが,これは見てのとおり「代入」です.変数 i にこの場合数値 の1を代入しています.for ループの中で使用する変数 i の 値を初期化しているわけですが,ここで注意が必要なのは,前回多くの人が間違 えていた以下のような処理です.

          i = rand();
      
          for(i=1; i<=10; i++)
      

      上では,1行目で変数 i に乱数の値を代入していますが,その直後に for 文で i に1を代入しています.for 文で使 用する変数はこのように初期化されるので,それ以前にたとえ値を持っていた としても,変更されます.気を付けて下さい.

      そのため,for 文の仮変数として使用される i, j, k, ... などは通常の変数名として使用しません.整数を扱う変数名としては,m, n, p, q などを使用するか,きちんとした名前をつけるかしてください.

    • 「式2」について

      「式2」は真偽値を判断するためのものです.教科書に書いてあるように,式2が 真であればループ内の処理(「文」)を実行します.偽になるとループを抜けるこ とになります.無限ループになる,もしくは,実行しない場合など,この式2も 原因となっていることがありますので,注意してください.

          for(i=1; i==10; i++)
      

      上のような場合,ループは一回も回りません.また,

          for(i=1; i=10; i++)
      

      では無限ループになります.

    • 「式3」について

      式3も無限ループを引き起こす可能性のある部分ですので注意してください.例 えば,次の例は教室のCの環境では動作しますが,別の環境では無限ループにな る場合がありますので,注意してください.

          for(i=1; i<=10; i=i++)
      

    • 複合演算子と変数初期値

      複合演算子を学習しました.これは,数学とは大きく異なり以下のような処理が可能なプログラム言語特有の機能でした.

          a = a + 1;
      
      

      これは変数 a の値に1を加えたものを新たに a に代入するというもので,これを複合演算子を用いて以下のように記述できます.

          a += 1;
      

      このとき,変数 a に初期値を与えていない場合,a の値が不定のままで代入作業が行われるので,処理系によってはとんでもない値が混じってしまうことになります.そこで,このような複合演算子を使用するときは必ずその前に値を代入しておかなければなりません.

      ただ,そうは言っても忘れてしまうこともあるでしょう.そのようなミスを未然に防ぐために,コンパイル時にコマンドにオプションをつけることで,警告を確認することができます.以下のプログラムは変数 a を初期化していない不適切なものです.

      #include <stdio.h>
      
      main()
      {
      	int a;
      	
      	printf("%d\n", a += 1);
      	
      	return(0);
      }
      

      私の使用している環境(Vine Linux)では実行結果は以下のようになります.

      -1075861099
      

      とんでもない値ですね.コンパイル時に以下のようにしてみましょう.

      $ cc -Wuninitialized hoge.c

      すると,以下のように警告が出てくると思います.

      hoge.c: 関数 `main' 内:
      hoge.c:5: 警告: `a' might be used uninitialized in this function
      

      これにより変な動作を未然に防ぐことができます.

      教室の環境では警告の文章は少し違っていますが,意味は同じです.
  5. 多重の for

    例題4.8では2重の for 文を使用して2次元の座標のような考え方を実 現しています.ただし,あまり良い例ではありません.もっと単純な2次元処理 を考えてみましょう.変数 i j を用意して以下のよ うな処理を考えると,

        for(i=1; i<=5; i++)
            for(j=1; j<=5; j++)
    

    以下のような座標的な処理が実現できますので,その位置で何をするか決めれば いろんな処理が出来ます.

    (1,1) (1,2) (1,3) (1,4) (1,5)
    (2,1) (2,2) (2,3) (2,4) (2,5)
    (3,1) (3,2) (3,3) (3,4) (3,5)
    (4,1) (4,2) (4,3) (4,4) (4,5)
    (5,1) (5,2) (5,3) (5,4) (5,5)
    

    例えば,そこで変数 i j の値を表示させてみるとよくわかるでしょう.

    	for(i=1; i<=5; i++)
    		for(j=1; j<=5; j++)
    			printf("(%d,%d)", i, j);
    

    ちなみに教科書の例題4.8を書き直すと以下のようになります.

    #include <stdio.h>
    
    main()
    {
    	int i, j;
    	
    	for(i=-5; i<=5; i++){
    		for(j=0; j<=i*i; j++)
    			printf(" ");
    			
    		printf("*\n");
    	}
    	
    	return(0);
    }
    
    

    #include <stdio.h>
    
    main()
    {
    	int i, j;
    	
    	for(i=-5; i<=5; i++){
    		for(j=0; j<=25; j++)
    			if(j==i*i)
    				printf("*");
    			else
    				printf(" ");
    				
    		printf("\n");
    	}
    
    	return(0);
    }
    

  6. 実習

    実習の演習問題予習分はこちら.他は当日ご案内します.

  7. 次回の予習範囲

    教科書のp.49の例題4.9を予習してきてください.ただし,前回と同様5行目でインクルード されている conio.h というヘッダファイルは教室の環境には無いので 使えません.これは12行目の clrscr() (クリアスクリーン)を使うた めのものなので,この行を削除すれば conio.h をインクルードしなく ても大丈夫です.

  8. 宿題

    授業の終わりに宿題の案内をします.ただし,問題を見ることができるのは1日以降です.

    10.184.10.130/report/

    にアクセスして問題を見てください.


目次ページに戻る