情報科学演習
2017.12.18

Back to index page



  1. 本日の作業内容

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

    小テストではエラーや無限ループのプログラムが毎回のように出てくるのですが,出しても採点はしないので,とにかく出さないでください.おねがいします.

    コンパイルエラー: b1704 b1736 b1512
    無限ループ: b1722

    今回も実行結果の最後にハイフンによる区分線のない人がいました.また,こんな簡単なプログラムでインデントの不備もありました.気をつけてください.

    ハイフンライン無し: b1749
    インデント(字下げ)不備: b1735 b1752 b1623

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

            i[0]=11;
            i[1]=53;
            i[2]=621;
            i[3]=1352;
            i[4]=20995;
    

    配列はもっと簡単に作れます.

            int a[5],b=rand()% 5+1 ,i;
            
            if(b==1){
                    a[i]=11;
                    }
            else if(b==2){
                    a[i]=53;
                    }
            else if(b==3){
                    a[i]=621;
                    }
            else if(b==4){
                    a[i]=1357;
                    }
            else{
                    a[i]=20995;
                    }
    

    if 文は不要ですね.

            int i= rand()%4+1, ary[5] = {11, 53, 621, 1357, 20995};
    

    発生させる乱数に問題がありますね.

            printf("Random number: %d\n\n", ary[5]);
    

    この配列には5番目の要素はありません.

            printf("Random number: %d\n",ary[10]);
    

    どうして添字が10になっているのか,意味不明です.

  3. 宿題の結果について

    今回から配列を扱い始めたので,これまでにはなかった警告が出る場合があります.具体的には配列の要素の個数を超えた添字を指定して処理を行った場合で,コンパイル後に実行すると,気の利いたシステムであれば以下のような警告が出るものです.(表示結果は使用環境によって少し異なる場合があります.)ただし,この教室では出ないことがあるようですが.

    *** stack smashing detected ***: ./a.out terminated
    中止 (コアダンプ)
    

    以下のように3人の学生さんが,そのようなプログラムを提出しています.今回は4点減点ですが,期末試験では採点対象外としますので,注意してください.

    コアダンプ: b1733 b1740 b1742

    その他,いつものようにハイフンラインが無いもの,解答用紙に番号と名前が無いもの,インデントの不備と,相変わらずの様子です.インデントについては,何度も言っていますが,わからない人は質問してください.

    ハイフンライン無し: b1749 b1762 b1775
    解答用紙に番号と名前無し: b1730 b1735 b1779
    インデント(字下げ)の不備: b1701 b1711 b1719 b1721 b1763 b1783 b1512 b1623 b1675 b1677 program1

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

            for(i=0; i<=9; i++){
                    a[i]=rand()%90+10;
                    printf("%d ",a[i]);
                    a[10]=a[i];
            }            
    

    よくわからない a[10]=a[i]; という処理がありますが,ここで配列の存在しない10番目の要素を扱おうとしているので,警告が出ます.

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

    こちらも配列に存在しない10番目の要素を扱おうとしているので,コアダンプです.

            for(i=0;i<=9;i++){
                    ary[i] = 0;
                    num = rand() % 90 + 10;
                    ary[i] = num;
                    printf("%d ",ary[i]);
            }
    

    変数の初期化についてうるさく言っていますが,初期化の意味がわかっていない例です.ここでは発生した乱数を ary[i] に代入するので,それ以前に0で初期化を行う必要はありません.

    不等号の < などで比較演算を行おうとする変数などに値がないとおかしいことになりますが,この場合は関係ないです.

            i = 0;
            for(i=0; i<10; i+=2){
                    printf("%2d    ",ary[i]);
            }
    

    for 文は式1で変数 i の初期化を行うので, for 文の前の i = 0; は不要ですね.これが必要なのは while 文です.

            int i,r,ary[10]={1,2,3,4,5,6,7,8,9,10};
    

    意味のわからない配列定義です.

            for(i=0;i<=9;i++){
                    ary[i]=rand()%90+10;
                    printf("%d ",ary[i]);
            }
            printf("\n");
            for(j=0;j<=9;j=j+2){
                    printf("%d    ",ary[j]);
            }
            printf("\n   ");
            for(k=1;k<=9;k=k+2){
                    printf("%d    ",ary[k]);
            }
    

    for 文は毎回式1で変数の初期化を行うので,上のように3回出てくるからといって,変数を i, j, k と変えていく必要はありません.全部 i だけで大丈夫です.

            printf("\n %d    %d    %d    %d    %d\n",num1[1],num1[3],num1[5],num1[7],num1[9]);
            printf("    %d    %d    %d    %d    %d\n",num1[2],num1[4],num1[6],num1[8],num1[10]);
    

    for 文と組み合わせて使えないダメダメな例です.さらに添字に10があるので,コアダンプまで引き起こします.

            for(i=0;i<9;i=i+2){
                    b[i]=a[i];
                    printf(" %d",b[i]);
                    printf("   ",b[i]);
            }
            printf("\n");
            
            for(i=1;i<10;i=i+2){
                    b[i]=a[i];
                    printf("   ",b[i]);
                    printf(" %d",b[i]);
            }
    

    無駄な配列 b を使用しています.

            int b[10];
            int i;
            int n = rand () % 5 + 3;
    

    この変数 n は何?古いプログラムの使い回しの際には,必要なものだけ残しているかをきちんと確認してください.

  4. 前回の復習

    配列を扱いました.配列は添字(インデックス)を使って中の値を参照するもので すが,その添字は記号を利用した数式でも構いません.そのため,for 文などと組み合わせて,たくさんの値を一度に代入したり,計算した りすることが可能です.これが配列の便利なところなので,今後も反復処 理と組み合わせて利用する実習課題を行っています.

    まず,配列の宣言ですが,

    	int ary[4];
    

    のように行います.ここで,配列 ary の次に数字の4がありますが,このように定義の文の中ではこれは要素の個数を表します.

    一方,プログラム中では添字として使われる数値は0から始まりますので,要素の個数が4個であれば,割り当てられているのは下図のように0から3までです.まずは,ここに注意してください.そして,添字として扱う場合には, ary[3] のようになると,これは配列の添字3の要素(4個目の値)を指すことにも注意してください.

    さて,上述のように定義すると,次の図のように整数値を入れるための入れ物(配列)が用意されます.

    また,以下のように定義すると,下図のように値が入った配列が用意されます.

    	int ary[4] = {5, 11, 2, 3};
    

    それから初期化について改めて注意しておきます.初期化がきちんと出来ているかどうかは以下のようにオプションをつけてコンパイルすることでわかります.

    $ cc -O -Wuninitialized hoge.c

    なお,初期化が必要なものは以下のように最初に値を利用するもので,代入であれば問題ありません.

    初期化が必要な例

    	int i;
    	
    	while(i>0)
    		hoge;
    

    	int i, a;
    	
    	for(i=0; i<=4; i++)
    		a += i;
    

    初期化が不要な例

    	int i, j, count;
    	
    	for(i=0; i<=4; i++);{
    		count = 0;
    		
    		for(j=0; j<=4: j++)
    			count++;
    	}
    

  5. 2次元配列

    2次元の配列は上の図で示したような入れ物が2重になっているもので,例えば以下のように表すことも出来ます.

    	int ary[3][4] = {{5, 11, 2, 3}, {4, 15, 6, 9}, {12, 13, 1, 7}};
    

    教科書p.54の図5.3にあるように2次元の配列を用意すると,マトリックス状にデー タを格納できます.これを利用して,表計算のようなことも出来ます.例えば, 次のような配列があるとします.

        ary[3][3] = {{11, 12, 13}, {21, 22, 23}, {31, 32, 33}}
    

    要素は例えば,ary[0][1] は12ですし,ary[2][0] は31です.

    このとき,ふたつ目のインデックス(添字)が1に関する和を取ると,12+22+32の 足し算となります.これがデータを行と列に並べた場合の列に関する和となりま す.

    111213
    212223一つ目の添字が1のものはこの行ary[1][j]
    313233
    2つ目の添字が1のものはこの列
    ary[i][1]

    また,マトリックス的なものでは無い多次元配列の使い方としては,前回説明し た温度測定の場合でもあります.1次元の配列だと,1日の温度のデータが格納で きるだけですが,次元を上げていくと次のようにも使えます.

    次元補足
    2 temp[18][0]
    temp[16][14]
    18日午前0時の気温
    16日午後2時の気温
    3 temp[12][18][0]
    temp[2][1][15]
    12月18日午前0時の気温
    2月1日午後3時の気温
    4 temp[15][2][1][16]
    temp[17][12][18][0]
    2015年2月1日午後4時の気温
    2017年12月18日午前0時の気温

    このように添字を使用すれば,後から値を読み出すときに変数を使用して簡単に 出来ます.

    	    year = 17;
    	    month = 12;
    	    date = 18;
    	    hour = 0;
    
    	    printf("%d\n", temp[year][month][date][hour]);
    

  6. 実習

    実習の演習問題(予習用)はこちらです.

  7. 次回の予習範囲

    教科書のp.66-70を予習してきてください.また,次回の授業では最初に文字列配列に関する小テストを実施しますので,文字列について予習をしっかりしてきてください.

  8. 宿題

    授業の終わりに宿題の案内をします.ただし,問題を見ることができるのは12日10時以降です.レポート提出システムから閲覧してください.


目次ページに戻る