情報科学演習
2016.11.28

Back to index page



  1. 本日の作業内容


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

    小テストの結果をまとめます.小テストでは時間のプレッシャーがあるので,コンパイルエラーなどの不備の答案がどうしても多くなります.が,それでもしっかり確認しましょう.

    コンパイルエラー: b1606 b1656 b1666 b1674
    解答用紙不使用: b1664 b1449

            int a=rand()% 89+10, b=a+20, i;
    
    
            int j = rand() % 89 + 9;
    
    
            n=rand() % 99 + 1 ;
    

    まずは乱数です.相変わらず乱数の発生範囲がわかっていない人が多く見られました.89や99という数字からいい加減離れてください.余りは割る数よりも必ず小さいんです.

            i = rand() % 100 + 10;
            
            printf("My student number: s164021\n\n");
            printf("Random number: ");
            
            for(i=10; i<=20; i++)
                            printf("%d", i);
    

    最初の行で何をやっても, for 文の式1で変数 i は初期化されるので,意味がありませんね.変数 i などは for 文の反復処理の回数や進み方を決めるためのものなので,乱数など他のものに使用しないくせをつけることが大事です.インデントもおかしいですね.

            for(i=1; i<=20; i++){
                    printf("%d ", b);
                    b = a+i;
                    }
    

    実行する順番がおかしいですね.表示してから足したのでは,手遅れです.

            for(i=1; i<=20; i++)
                    
                    printf("%d ",a);
                    a+=i;
    

    for 文の基本は中括弧 { } でブロックをつくることです. if 文と同じように,1行だけなら中括弧の省略も可能ですが,2行以上に渡る場合には必須です.

            a       =       rand () %90 + 10;
            for(i=1; i<=20; i++){
                    a       =       rand () %90 + 10;       
                    printf("Random number: %d\n", a);
                    printf("%d", i);
            }       
    

    スペースの代わりにTABを入れられると見づらいのでやめるように何度も言っているのに,なぜ直らない,b1630!

            for(i = 1;i <= 20;i ++)
            printf("%d ",a + i);
    

    上のようなインデントの不備は大量に見られました.ブロックというものを意識して,プログラムの作成中からインデントは入れてください.

  3. 宿題の結果について

    コンパイルエラーは今回なくなりました.一安心です.しかし,内容に関しては直す点がたくさんありましたので,例によって以下に一部を例示します.参考にしてください.なお,今回は for 文が出てきた関係でインデント(字下げ)が一層複雑になりました.その分,インデントの不備も多くなりました.以下に該当者を示しますので,自分の解答を見て間違った点を確認しておいてください.

    インデントの不備のある該当者: b1390 b1601 b1603 b1609 b1611 b1612 b1614 b1617 b1620 b1621 b1635 b1636 b1638 b1643 b1648 b1651 b1652 b1653 b1656 b1657 b1670 b1675 b1679 b1680 b1393 b1461 b1484 b1445 b1569 program4

    それから今回は満点が5人しかいませんでした.理由は3つ目の for ループの前の変数の初期化をしていない人が大半だったからです.符号のための変数の値が1になるか-1になるかは直前の for 文の反復回数によって変わります.ですので,念の為初期化を行っておきましょう.そうすると,反復回数を乱数で指定するような問題にもそのまま対応できます.

    また,3つ目の for 文は逐次和を求めていくと実現できるのですが,その際の和を代入する変数の初期化を行っていない人も多く見られました.前にも言いましたが,教室の環境ではたまたま0が初期化されていない場合に入るので,他の環境ではとんでもない値になることがあります.必ず初期化しましょう.

            for(i=-1,a=-1; i>=-10; i--,a*=-1){
                    printf(" %3d ", i*a);
            }                       
    

    上のようなやり方は教えておりません.使わないようにしましょう.

    以下はインデントに問題のあるものの一例です.

            for(a=1; a<=10; a++){
                    f *= -1;        
                            printf("%3d ",f*a);             
            }
    

    なぜ, printf が下がる?

            for(i=1; i <= 10;i++){
            printf("%4d",i);
            }
    

    典型的な間違い.中括弧に囲まれたブロックは字下げします.

            for(i=1; i<=10;i++){
                    printf("%3d ",i);
            }       
                    printf("\n");
    

    なぜ, for 文の外の printf が下がる?

            printf("---------------------------------------\n\n");
            
    return(0);
    }
    

    相変わらず見られました.最後に注意がおろそかになる例です.

  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++)
      

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

      式2について,「終了条件」のように間違って理解している人が時々見られます.式2は終了条件ではなく実行条件です.

    • 「式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. 宿題

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

    10.184.10.128/report/

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


目次ページに戻る