情報科学演習
2013.11.25

Back to index page



  1. 本日の作業内容


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

    エラーの出る答案が以下のように提出されています.また,無限ループもありました.これらは提出されても採点しないので出さないようにお願いします.

    コンパイルエラー b1328 b1337 b1374 b1008 b1106

    無限ループ b1340

    解答用紙不使用 b1331

    以下は問題のある答案ですが,すでに自分でも分かっていると思います.以後は気を付けましょう.

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

    0から20までになっています.

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

    インデントもおかしいですが,不要な変数を使用していることの方が問題です.変数 sum は要りませんね.しかも和では無いし.

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

    これも不要な変数 sum がありますし,さらに不要な処理までやってます.

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

    これもインデントがおかしいのですが,その前に for の行と実際に繰り返す処理の printf の行の間に空行は入れないでください.関係がわかりにくくなります.空行は処理の切れ目や意味の違う処理が出てくる際にわかりやすくするために入れるものです.

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    main()
    {
        srand((unsigned) time(NULL));
    

    乱数は使いませんでしたよね.

            for(i = 0; i <= 19; i++)
            printf("%d\n",i + 1);
    

    改行が問題です.

            printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d \n\n" ,num);
    

    ほとんどマイナス100点の処理です.

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

    ここに if 文まで使って改行を入れることは無いですね.

    以下はインデントのおかしい例です.

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

    もう今後このようなことは無くなりますよね?

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

    また出ました.古いプログラムの流用は止めて自分で書いてください.それで防止できるはずです.

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

    今回はこのような逆パターンも出てきました.

            for(i=1;i<=20;i++)
                    printf("%d ",i);
                    printf("\n\n-----------------------------\n\n");
    

    上の printf は繰り返す処理なので for に従属する文ですから字下げします.しかし,下の printf は反復処理では無いですね.for 文とは関係ないものなので,下げる必要はありません.

            main()
    {
    

    以前にも指摘しましたが,main は下げません.亡霊のように復活してきました.

  3. 宿題の結果について

    今回はトラブルになる答案がたくさん出てきました.採点しませんので,注意してください.

    コンパイルエラー b1308

    無限ループ b1347

    解答用紙不使用 b1322 b1348

    実行時エラー b1274

    前回の小テスト提出 b1282

    さて,以下は和を求める際に変数の初期化をしていなかったために正しい値が出ないものです.今回は初回だったので-2点ということにしますが,次回以降はもっと点を引きますので,注意してください.

    b1301 b1304 b1315 b1317 b1324 b1325 b1326 b1331 b1332 b1333 b1334 b1339
    b1343 b1344 b1346 b1350 b1352 b1353 b1354 b1357 b1360 b1361 b1362 b1364
    b1367 b1368 b1369 b1370 b1375 b1377 b1379 b1383 s131108

    過年度生にも初期化ができていない人がたくさんいました.残念です.

    b0983 b1064 b1072 b1204 b1206 b1216 b1223 b1251 b1257 b1269 b1270 b1284

    以下はいつものように問題のある答案です.個々に説明していますが,どうおかしいのか分からない場合にはちゃんと質問をして解決しましょう.

            printf("%d\n",num);
            printf("%d",num / 10000000);
            printf(" %d",num % 10000000 / 1000000);
            printf(" %d",num % 1000000 / 100000);
            printf(" %d",num % 100000 / 10000);
            printf(" %d",num % 10000 / 1000);
            printf(" %d",num % 1000 / 100);
            printf(" %d",num % 100 / 10);
            printf(" %d\n",num % 10);
            for(i = 1; i <= 8; i++)
                    num += i;
            printf("Sum of above digits: %d\n",num / 10000000 + num % 10000000 / 1000000 + num % 1000000 / 100000 + num % 100000 / 10000 + num % 10000 / 1000 + num
    % 1000 / 100 + num % 100 / 10 + num % 10);
    

    今年度初めて出ました.絶対にやっちゃだめ!マイナス100点の答案です.こういうことをしないために for 文があります.

            int i, a = rand() % 10000000 + 9999999,b = a,num = 0;
    

    どんな数を出そうとしているのか?

            num=rand()%90000000-10000000;
    

    負の数が出るのでは?

            for(i=1;i<=8;i++){
                    b /= 10;
                    a %= b;
                    c = a/(b/10);
                    printf("%d ",c);
            }
            printf("\n");
            printf("Sum of above digits: %d\n",c);
    

    += で和を求める処理が無い!

    ここからはインデント(字下げ)の問題です.あいかわらず多いです.

            printf("%d\n",num);
    
            for(i = 10000000; i>=1; i/=10){
             q = num / i;
             num %= i;
             sum += q;
    
            printf("%d ",q);
         }
    

    好き勝手なことをしていますね.

                    for(i = 1; i <= 8; i++){
                            printf("%d ",num/j);
                            sum += num / j;
                            num %= j;
                            j /= 10;
                    }
                    printf("\n");
                    printf("Sum of above digits: %d\n\n",sum);
                    printf("----------------------------------\n\n");
                    return(0);
    }
    

    下げればいいってものでは無いです.最初はタブ2個分,for の中はタブ1個分は変です.

        for(i=10000000;i>=1;i/=10){
            div = num / i;
                div %= 10;
                    printf("%d ", div);
            sum += div;
        }
    

    なんで for の中の文がどんどん下がるのでしょうか?

            for(i=1; i<=8; i++){
                    printf("%d ", a/b);
                            c += a/b;
                            a = a-(a/b)*b;
                            b /= 10;
    

    これもなぜ字下げの量が変わるのでしょうか?

    main()
    {
        srand((unsigned) time(NULL));
    
            printf("My student number: s134027\n\n");
    

    また出ました.

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

    上の2つはコピペをした際の残骸がまだ残っているものです.何度も言っていますが,一度自分できちんと入力しましょう.

  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. 宿題

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

    10.184.10.130/report/

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


目次ページに戻る