プログラミング入門I
2021.12.20

Back to index page



  1. 本日の作業内容

  2. 前回の宿題について

    さて,今回は困った事態になってしまいました.厳密に対処すると大変面倒な事になってしまうので,今回だけ採点対象外ということにしておきますが,以下の学生さんには厳重注意を与えておきます.次は無しですぜ!

    厳重注意: b2065

    今回特徴的だったのは一応無限ループでは無いものの,ほぼ無限ループに近いプログラムです.原因は後述しているのですが,それにより実行時間が非常に長くなるものです.申し訳ありませんが,採点の対象外として削除しました.

    ほぼ無限ループ: b2108 b2111 b2121 b2124 b2125 b2126 b2127 b2134 b2136 b2155 b2157

    始めてコアダンプも出ました.値の出る範囲には注意しましょう.

    コアダンプ: b2118 b2165

    で,残念ながらコンパイルエラーもありました.こちらも提出前によく確認しましょう.

    コンパイルエラー: b2149

    不適切なインデントはちょっと減ってきたようですが,まだまだ出てきます.こちらも注意しましょう.

    不適切なインデント: b1734 b1825 b2111 b2139

    以下は例によって問題のあるプログラムの例です.参考にしてください.

        int num = rand() % 1000 + 1;
    

    相変わらず乱数の不適切なものが出ています.3桁の正の整数と指定しましたが,上の指定では1桁や2桁の数も出てしまいますね.

        int i, num = rand() % 899 + 101;
    

    こういうよくわからないものも出ました.上の指定では,101から999の範囲ですね.

        int num = rand() %900 + 100;
    
        while(num != 1)
        {
            num = rand() %(num-1) + 1;
            printf("%d ", num);
        }
    

    上のようなものも何件か出ました.最初にちゃんと3桁の正の整数を乱数で発生させているのに,それを表示させる命令がありません.なので,場合によっては2桁の整数から表示が始まってしまうことになります.

        int num; 
    
        while(num > 1) //乱数1が出るまで乱数発生を繰り返す
        {
            num = rand() % 999 + 1; //3桁の正の整数を乱数により1個発生させる。
            if(max > num) //発生させた乱数が、前に発生した乱数より小さければ、それを出力する
            {
                printf("%d ",num);
                max = num; //変数maxの中身を新しく出力させた乱数に置き換える
            }
        }
    

    発生させる乱数も間違っていますが,それよりも問題は変数の初期化です.int 型の変数 num を宣言しましたが,初期化されていません.すなわち値は不定です.なので,while() 文で num > 1 の場合のみ実行するようになっていますので,while() 文の中身が一度も実行されないということが起こります.

        int random, small;
    
        random = rand() % 900 + 100;
        
        printf("%d ", random);
    
        while(small > 1)
        {
            random -= 1;
            
            small = rand() % random + 1;
    
            printf("%d ",small);
    
            random = small;
        }
    

    こちらも同様で,変数 small の値を初期化しないまま while() 文の式で使用していますので,while() 文が実行されないままになることがあります.

        while(num !=1)
        {
            num = rand() %(num-1) +1;
            printf("%d",num); 
        }
    

    printf() 文の中が "%d" なので,実行すると以下のような表示になります.

    6014827359544951
    

    わかりにくいったらありゃしない! ということで,結果がわかりづらいですね.減点です.

            i = rand() % i-1 + 1;
    

    動作としては問題ないのですが,単項演算子の - を使わないで,普通に括弧で i - 1 をくくって欲しいと思います.

        int num , min = 1000;
        num = rand() % 900 + 100;
    
        while(min > 1)
        {
            if(num < min)
            {
                min = num;
                printf("%d " , num);
            }
            num = rand() + 1;
        }
    

    で,今回ほぼ無限ループになった原因がこれです.桁数を指定しない乱数を適当に発生させて,たまたま小さくなったら採用する,という方針のプログラムですが,Windows 以外の環境,例えば UNIX 系のCコンパイラでは発生させる乱数の最大値が非常に大きいので,ずっと乱数の発生を繰り返し続け,ほぼ無限ループということになります.このような使用法ではなく,解答例のように発生する乱数自体をだんだんと小さくしていくという発想に至って欲しかったです.

    最初に発生させる乱数が3桁の整数なので,せめて3桁の整数にしておけばこんなことにはならかったのにね.残念.
  3. 前回の復習

    前回はちょっと凝った反復処理のプログラムを試しました.どんな風にプログラムすれば狙った動作になるのか,今後もじっくり考えて下さい.

  4. 多重の for

    for 文の中にまた for 文を入れることで様々なことが可能になります.例えば,2次元的な画面表示があります.今回は,画面に座標的な出力を行うことを学習します.

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(void)
    {
        srand((unsigned) time(NULL));
    	
        int i, j;
    	
        for(i=1; i<=5; i++)
        {
            for(j=0; j<25; j++)
            {
                printf("%d ", j);
            }
    		
            printf("\n");
        }
    	
        return 0;
    }
    

    基本的には,外側のループで行を縦にすすめる制御を,内側のループで行内を右へ表示していく作業を行っています.

    乱数を使って行ごとに異なる数の●を表示させる以下のようなプログラムを考えましょう.

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(void)
    {
        srand((unsigned) time(NULL));
    
        int i, j, dots;
    
        for(i=1; i<=3; i++)
        {
            dots = rand() % 4 + 1;
    
            for(j=1; j<=dots; j++)
            {
                printf("● ");
            }
    
            printf("\n");
        }
    
        return 0;
    }
    

    このプログラムの動作を理解してもらうための,紙芝居的なページも別に用意しましたので,必要に応じてご覧ください.じっくり見て動作を確認してもらえれば幸いです.

    ただし,発生する乱数は4,3,1と固定されていますので,ご注意ください.
  5. 実習

    実習の演習問題は当日ご案内します.

  6. 次回の予習範囲

    引き続き多重の for 文を扱います.予習用の課題を見ておいてください.

  7. 宿題

    宿題はレポート提出システムを利用します.今回は提出は1月17日になってしまいます.間がかなり開くので,忘れないように注意してください.


目次ページに戻る