情報科学演習
2013.01.21

Back to index page



  1. 本日の作業内容

  2. 宿題の結果について

    すみません.宿題の説明文に足らない情報がありました.修正してアップロードしているので,もう一度問題を良く見てください.

    さて,上記のようにお騒がせしましたが,採点は通常どおり行いました.例によって,以下に問題のあるものの例を示して行きます.

    また,愚か者が出てきました.海より深く反省してください.なお,単位が要らない場合には話が早いので私まで連絡をお願いします.

    b1275 b1287

    コンパイルエラーもありました.

    b1133

    解答用紙の不使用もなくなりません.

    b1219

    セグメンテーション違反もありました.

    b1153

    以下は中身の問題です.

                    for(j=0;j<=7;j++){
                            printf("%c",subject[i][j]);
                    }
    

    文字列の長さを超えて表示させていますので,本日のテキストにあるようなヌル文字の表示の問題が発生しています.

                    k=rand()%3;
                    for(l=0;l<=2;l++){
                            score[l][j]=rand()%50+51;
                            if(k==0)
                                    score[0][j]=0;
                            if(k==1)
                                    score[1][j]=0;
                            if(k==2)
                                    score[2][j]=0;
                    }
    

    余分な if の処理です.

                    r=rand()%3;
                    if(r==0){
                            a[i][0]=0;
                            a[i][1]=rand()%50+51;
                            a[i][2]=rand()%50+51;
                    }
                    else if(r==1){
                            a[i][0]=rand()%50+51;
                            a[i][1]=0;
                            a[i][2]=rand()%50+51;
                    }
                    else{
                            a[i][0]=rand()%50+51;
                            a[i][1]=rand()%50+51;
                            a[i][2]=0;
                    }
    

    このようなくどい処理が必要なプログラムは課題に出しませんので,以後は注意してください.

            for(i=0;i<10;i++){
                    a=rand() % 3;
                    b=rand() % 50 + 51;
                    c=rand() % 50 + 51;
                    if(a==0){
                            ary[0][i]=b;
                            ary[1][i]=c;
                            ary[2][i]=0;
                            bry[0]+=1;
                            bry[1]+=1;
                    }
                    else if(a==1){
                            ary[0][i]=0;
                            ary[1][i]=b;
                            ary[2][i]=c;
                            bry[1]+=1;
                            bry[2]+=1;
                    }
                    else{
                            ary[0][i]=c;
                            ary[1][i]=0;
                            ary[2][i]=b;
                            bry[0]+=1;
                            bry[2]+=1;
                    }
                    sum[0]+=ary[0][i];
                    sum[1]+=ary[1][i];
                    sum[2]+=ary[2][i];
            }
    

    同じく,このような処理はやっちゃダメです.

            char subject[3][8] = {"English", "Math   ", "Physics"};
            
            char subject[3][9] = {"English:", "Math   :", "Physics:"};
    

    指定した配列と違います.ごまかさないで下さい.

            printf("Student:    1    2    3    4    5    6    7    8    9   10 Average\n");
    

    こういうのは for 文を使用してください.もし学生の人数が1万人,100万人だったらどうしますか?

                    }
    
            printf("%8.1f\n",ave[j]/=b);
            }
    

    最近上のようなインデント(字下げ)のおかしい例が毎回出てきます.中括弧 { } の中の処理では閉じ中括弧と頭の位置が同じになることはありません.

                    for(i=0 ; i<3 ; i++){
                                    printf("%-7s:", subject[i]);
                                    for(j=0 ; j<10 ; j++){
                                                    ran2=rand() % 50 + 51;
                                                    if(ran1[j] == 0){
                                                                    if(i == 0){
                                                                                    printf("%5d", ran2);
                                                                                    sum+= ran2;
                                                                                    a++;
                                                                    }
                                                                    else if(i == 1){
                                                                                    printf("%5d", ran2);
                                                                                    sum+= ran2;
                                                                                    a++;
                                                                    }
                                                                    else
                                                                                    printf("     ");
                                                    }
                                                    else if(ran1[j] == 1){
                                                                    if(i == 0){
                                                                                    printf("%5d", ran2);
                                                                                    sum+= ran2;
                                                                                    a++;
                                                                    }
                                                                    else if(i == 2){
                                                                                    printf("%5d", ran2);
                                                                                    sum+= ran2;
                                                                                    a++;
                                                                    }
                                                                    else
                                                                                    printf("     ");
                                                    }
                                                    else{
                                                                    if(i == 1){
                                                                                    printf("%5d", ran2);
                                                                                    sum+= ran2;
                                                                                    a++;
                                                                    }
                                                                    else if(i == 2){
                                                                                    printf("%5d", ran2);
                                                                                    sum+= ran2;
                                                                                    a++;
                                                                    }
                                                                    else
                                                                                    printf("     ");
                                                    }
                                    }
                                    printf("%8.1f", ave=sum / a);
                                    printf("\n");
                    }
    

    インデントの幅が大きすぎて見づらいですが,処理も何をやっているのかわかりませんでした.

            int point[3][10] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
    

    今回は減点していませんが,以後はこのような初期化の方法は止めましょう.学生の人数や科目がもっと多かったらどうしますか?

        for(j=0; j<10; j++){
            a = rand() % 3;
            for(i=0; i<3; i++){
                  if(a != i)
                                       point[i][j] = rand() % 50 + 51;
                  else
                     point[i][j] = 0;
                     }
             }
    
        for(i=0; i<3; i++){
                     b = 0;
                     n = 0;
                     printf("%-7s:", subject[i]);
                     for(j=0; j<10; j++){
                  if(point[i][j] != 0)
                      n += 1;
    
                  if(point[i][j] == 0)
                      printf("     ");
                  else
                      printf("%5d", point[i][j]);
    
                  b += point[i][j];
                    }
                    printf("%8.1f\n", b/n);
            }
    

    この異常に変なインデントのプログラムが2つ出てきました.どうしてでしょう?

                            if(j == a)
                                    num[j][i] = 0;
    
                            if(j != a)
                                    num[j][i] = rand() % 50 + 51;
    

    前回説明しましたが,必ずどちらかになる場合には if の羅列では無く,else を使いましょう.

  3. 初期化

    前回の授業で,宿題の計算が間違っている例として和を求める変数の初期化がなされていないことに言及しましたが,実はC言語の変数の初期値に関しては統一の規定が無いために,教室環境のように自動的に0を入れてくれるものや,広く普及しているGCC(GNU C Compiler)のように不定のままのものなど,多様な仕様が存在しています.

    そのため,みなさんは初期値を入れる(初期化する)こと無しに変数を使うという悪い癖が身についてしまっているようです.これについては,Yahoo知恵袋などでも紹介されていますので,良く読んでおいて,以後は注意してください.

    http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1421060754 http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1449816014

    実際に採点する環境はGCCを使用しているので,初期化が行われていないのに複合演算子を使用した場合,間違った答えが出てきます.自分で気づかないうちに減点されるので,うっかりミスは致命的です.
  4. 前回の復習

    配列以前に,変数の値の入れ換えができない人が見られました.値の入れ換えは数値や文字の並べ変えを理解する際の基本ですので,これができないと実際のプログラミング課題に困難が生じます.復習や質問をしっかり行って理解を深めて下さい.

    演習問題の iii iv において,作成する配列のサイズがおかしいケースも多く見られました.9個の乱数を3×3の2次元配列に格納することをまず行って,それから各種の計算に進むことを求めていますので,変なサイズの配列を作ってしまわないようにお願いします.

    vi 番の課題では配列の要素を添字を規則的に順送りすることで行列式の計算に繋げることを要求しています.ここでは,これも以前から何度も強調している「剰余」がポイントです.3行3列の行列の要素ですので,配列の添字としては0から2の3種類しか出てきません.012と進んだ後,3に行くのでは無く0に戻るためには3の剰余が使えます.これもよく確認しておいて下さい.

  5. 文字列配列

    C言語では文字列(abc shimane のような文字の組)は配列 となります.それぞれの文字は配列の要素として利用可能です.文字列に関して は以下のような注意が必要です.

    • ヌル文字

      文字列の最後には文字列の終わりを意味するヌル文字 \0 があります. これは目には見えませんが,必ず付いているものです.ですので,配列の要素の 個数は文字数+1にしておく必要があります.

      実際にNULL文字が存在するのかは以下のようなプログラムで確認することが出来 ます.

      #include <stdio.h>
      
      main()
      {
      	int i;
      	char str[4]="abc";
      	
      	for(i=0; i<=4; i++)
      		printf("%c", str[i]);
      	
      	printf("\n");
      	
      	return(0);
      }
      

      このプログラムでは,for 文で実際には存在しない配列 str の4文字目までを出力することになっています.しかし,そこにはNULL文字が入っているのですが,NULL文字自体は通常の端末では目に見えません.そこで,標準出力(画面)への出力結果を整形して表示するページャと呼ばれるソフトにその表示処理を預けてみると,確認できます.

      $ ./a.out | less

      通常の実行コマンドの後に縦棒 | に続けて標準のページャソフトである less を指定することで,UNIXのパイプという機能を使用して出力を渡すことができます.結果はどうでしたでしょうか?

      なお,less を終了するには,キーボードから q を入力してください.文字列配列を使用したプログラムの実行は,このように必ず処理を less に渡すようにしてください.これでうっかりミスが防止できます.

    • 文字としての数字

      見た目には区別しにくいですが,char 型で定義すると数字も文字にな り,四則演算はできなくなります.注意してください.次の配列は数値です.

          int ary[2] = {1, 2};
      
          printf("%d\n", ary[0]+ary[1]);
      
      

      しかし,次のものは文字なので,計算には使用できません.

          char str[3] = {'1', '2', '\0'};
      
          printf("%d\n", str[0]+str[1]);
      

    • static 宣言

      教科書のp.59からは初期化のところで,auto (省略可)と static の宣言の話が出てきます.この授業の範囲では auto で構 いませんので,特別に宣言することは不要です.

    • %s %c

      教科書では配列の要素としての文字列を printf を用いて出力する際 に %s を使用しています.教科書のp.21にあるように,%s は「文字列」を表示させるものです.一方,文字列の中の「一文字」を出力する 際には %c を使用します.この違いに注意してください.本日の実習 では,主として %c を使用します.

      #include <stdio.h>
      
      main()
      {
      	int i;
      	char str[4]="abc";
      	
      	for(i=0; i<=3; i++)
      		printf("%c", str[i]);
      	
      	printf("\n");
      	
      	printf("%s\n", str);
      	
      	return(0);
      }
      

  6. 実習

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

  7. 次回の予習範囲

    次回はこれまでの総復習です.特別の予習範囲はありませんが,これまで分かっ ていない部分をしっかり把握してください.

  8. 宿題

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


目次ページに戻る