情報科学演習
2014.01.16

Back to index page



  1. 本日の作業内容

  2. メンター学習室について

    メンター学習室の開設時間は以下のように予定していますので,御利用下さい.

    1/15 1/17 1/22 1/29 2/5

    時間はいずれも14:30-16:00です.

  3. 小テストについて

    授業の最初に文字列に関する小テストを実施します.いつものように柱の部分を避けて席について下さい.

  4. 宿題の結果について

    今回も残念ながら採点できない答案がありました.気を付けてください.

    コンパイルエラー b1341
    関係ない課題提出 b1308
    解答用紙不使用 b1371

    また,解答用紙に名前の記載の無いものや学生番号が正しくないものが相変わらず相当数見られます.こちらも減点ですので注意してください.

    では,いつものように問題のある解答の例です.

            int i,j,k,sum,temp,num1,num2,ary[5][5]={0,0,0,0,0};
    

    2次元の配列なのに,1次元のように初期化しています.これはエラーにはならないのですが,処理としては中途半端なものです.自分で実際にどういう動作をするのかを理解し敢えて使うのならわかりますが,これはミスですね.

            int a[5][5] ={{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 文があります.面倒なことは計算機にやらせましょう.

            int a[5][5];
            int b[5][5];
    

    二つ配列を用意する必要はありません.メモリの無駄遣いですね.

                            ary[i][j] = rand() % 99+1;
    

    まだ乱数が分かってない人がいます.早く質問をして解決してください.

            for(i=0;i<4;i++){
                    for(j=i+1;j<6;j++){
    

    大小比較を行って入れ換えする際に,要素の無いところまで for 文で処理しようとしています.

            for(i=0;i<5;i++){
                    for(j=i+1;j<5;j++){
    

    これも上と同様に要素の無いところまで処理がなされています.ですので,このような間違いがあると変な数値が出てきます.初期化の確認オプションで確かめてください.

                            if(total[i]<total[j]){
                                    tmp=stu[i];
                                    stu[i]=stu[j];
                                    stu[j]=tmp;
    
                                    tmp=ary[i][0];
                                    ary[i][0]=ary[j][0];
                                    ary[j][0]=tmp;
    
                                    tmp=ary[i][1];
                                    ary[i][1]=ary[j][1];
                                    ary[j][1]=tmp;
    
                                    tmp=ary[i][2];
                                    ary[i][2]=ary[j][2];
                                    ary[j][2]=tmp;
    
                                    tmp=total[i];
                                    total[i]=total[j];
                                    total[j]=tmp;
                            }
    

    こちらも,このような処理を行うために for 文があります.

            for(i=0;        i<5;    i++){
                    k = 0;
                    ary[i][0] = 65+i;
                    printf("%7c  ", ary[i][0]);
                    for(j=1;        j<4;    j++){
    

    これは処理の間違いでは無いのですが,スペースを空けるべきところにTABが入っているので,見づらいプログラムになっています.

    Student  English     Math  Physics    Total        ^A
    

    文字列を扱うときにはページャの less に実行結果を引き取ってもらって画面で確認する癖をつけましょう.上記のようなごみが混入するのを防ぐことができます.

    Student^@  English^@  Math^@^@^@^@  Physics^@  Total^@^@^@
    

    これも同じで,less を使うと上記のようにおかしいことが確認できます.

    以下はインデントの不適切なものです.

            for(i=0; i<5; i++){
                    for(j=0; j<8; j++){
                            printf("%c", header[i][j]);
                    }
                    printf("  ");
            }
    

    最初がTABが2個,次も2個,次は1個と,インデントする際のTAB幅が統一されていません.TAB一つでお願いします.

        for(i=0;i<=3;i++){
            for(j=i+1;j<=4;j++){
                    if(stu[i][4]<=stu[j][4]){
                            for(k=0;k<=4;k++){
                                    tem=stu[i][k];
    

    これも途中でTAB幅が変わっています.

            for(i=0;i<=4;i++){
                    score[i][4]=0;
                    score[i][0]=65+i;
                    for(j=1;j<=3;j++){
                    score[i][j]=rand()%101;
                    score[i][4] += score[i][j];
                    }
            }
    

    内側の for の中が下がっていません.

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

    これもTAB幅が統一されていません.

  5. 初期化

    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

    初期化を忘れることを防ぐためには何度も書いていますが,以下のようにオプションを利用してください.

    $ cc -Wuninitialized hoge.c

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

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

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

  7. 文字列配列

    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);
      }
      

      これも以前に書きましたが,二重引用符 " " で囲まれたものは文字列です.ですので,目に見えないヌル文字が最後についています.一方,引用符 ' ' で囲まれたら1文字です.ですので,その場合にはヌル文字はついていません.

  8. 実習

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

  9. 次回の予習範囲

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

  10. 宿題

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


目次ページに戻る