プログラミング入門I
2021.10.25

Back to index page



  1. 本日の作業内容

  2. 前回の宿題について

    さて,初めての課題の提出でしたが,予想通りいろいろと問題のあるものが出てきました.例年最初はそうなるのですが,今年度は私の予想を超えるものがあり,Z世代の方々の考え方についてどうにも理解が難しいと感じました.

    さて,まずは基本的なことからですが,課題の提出は必ず解答用紙を使用してください.解答用紙はレポート提出システムで問題と一緒に見えるようにしてあります.開いて中身をコピーするのでも,ダウンロードするのでも構いません.必ず解答用紙に自分のプログラムを入力してください.解答用紙を使用していないものは採点の対象外となります.大勢のプログラムを一気に閲覧する上で,解答用紙を使用していないと各人のプログラムの切れ目や学生番号・氏名が分からず面倒になるからです.

    解答用紙不使用: b2101 b2107 b2109 b2142

    解答用紙には,見本として学生番号S216099,そして氏名は島根太郎があらかじめ入れてあります.あくまで見本,記入例です.そこを自分の学生番号と氏名に変えてください.

    解答用紙の学生番号と名前の間違い: b2126 b2157

    他にも解答用紙にはあらかじめ最後にハイフンによる線引きを行うように printf() 文があります.それを勝手に消さないでください.各人ごとの区切りがわかりにくくなり,採点が面倒になります.

    ハイフンライン無し: b2106

    そして,実行した際に自分の学生番号が出力されるように,解答用紙には学生番号出力のための printf() 文が入れられており,見本(記入例)としてS216099番が入っています.でも,そこは自分の学生番号に当然変えてください.

    S216099の出力: b2134

    で,今回はコンパイルエラーが1件出てきました.コンパイルエラーになるプログラムも当然採点の対象外です.原因は解答用紙の理解が不十分であったことと,C言語のプログラムの記述の約束事の理解の不足です.今後は気をつけましょう.

    コンパイルエラー: b2110

    そして,最後になりますが,インデント(字下げ)が不適切なプログラムが以下のように結構な数出てきました.教科書やWebテキストの例にあるように,C言語ではインデント(字下げ)によってプログラムの構造を見やすく表現する手法が使われています.AIで使用されることでここ最近注目されている言語のPythonなどではインデントが間違っていると動作自体ができなくなりますが,C言語はそこまで厳密でなく,動作するにはします.ただ,作成した人以外がソースコードを観る際に,非常にわかりにくくなりますので,作法・礼儀としてインデントはしっかり守ってください.

    とりあえず,現状で覚えておくことは中括弧 { } が出てきたら,その中身はTAB一個分字下げする,ということです.必ずTABを使用してください.自分でスペースを一つずつ入れるようなことをしていると,どこかでズレてきます.必ずTABでお願いします.なお,VS CodeではデフォルトでTABを打つとスペースが4個入ります.

    不適切なインデント: C001 b2103 b2126 b2130 b2137 2143 b2149 b2157 b2160

    さて,以下に示すのはよくないプログラムの例です.参考にしてください.

        char BaseVb = rand() % 26 + 65 ;
    

    C言語に限定すれば問題無いとも言えるかもしれませんが,言語はたくさんあり,他の言語との整合性なども考えると,変数名は小文字で始めましょう.大文字で始まると変数ではなく定数として扱う言語もあります.

        int str = rand();
        printf(
            "Random number:%d\n",str
            );
    

    今回実に多くの人が誤解していたのが,この乱数の表示の部分でした.問題文のところには, アルファベットの大文字をどれか一つ乱数を用いて発生させて表示しと書いてありました.この乱数を画面に表示させなさいという意味です.なので,最初の大文字はこの乱数を元に表示させたのですよ,ということを確認するために表示する必要があったのです.ところが,多くの人がアルファベットとは別に発生させた乱数を出力していたので,残念ですが減点させてもらいました.分かってもらえなくて残念です.

    printf() 文の中での改行も本来はやめておきましょう.あまりに長いときはまた考える必要もありますが.
    // ///////////////////////////////////////////
    //
    // 2021/10/19
    

    解答用紙の日付けは課題の提出日ではなく,課題を課した日ですので,ここは勝手に変えないで下さい.

        int num1 = rand()%27+64;
    

    アルファベットは26文字です.

    発生したアルファベット(大文字):B
    その次のアルファベット(小文字):c
    

    勝手に出力形式を変えないで下さい.あくまで出題された要件どおりに出力してください.なお,私のプログラムでは日本語は使用しません.英語で全て表記するようにしています.せっかくなので,英語の勉強もしてください.

        printf("Characters: %c%c\n", omoji , omoji+1+32);
    

    間違ってはいません.しかし,なんで omoji+1+32 と,3つの項が必要なんでしょうかね?

        char c, d;
    

    変数は1個だけの使用,と,問題文に明記しています.勝手なことをしないでください.

        int oniku = rand() % 26+65;
    

    この上のような変数名は適切ですか?

        int algorithm = 'A'+ rand() % 26 ;
    

    こちらもそうで,変数名として適切でしょうか.プログラムは自分1人がわかればいいというものではありません.人が見た時に,理解しやすい変数名をつけることを日頃から意識してください.

        printf("Random number: %d  \nCharacters: %c%c\n", letter, letter, letter + 33);
    

    間違ってはいません.ただ,1行が長いプログラムは見づらいです.元々の出力が2行なので,printf() 文も2つ使って分かりやすくしましょう.

    宿題の解答例のページ

    今回のプログラムのポイントは,変数をむやみに定義しないで四則演算を活用して,printf() で表現することでした.これまで何年も授業をやってきて,どうもプログラミング学習を始めた頃にはつぎつぎと変数を定義して printf() の中で使うと人が多いようで,無駄に変数を作ることが気になっていました.解答例を参考に, むやみやたらと変数を作らないよう今後も気をつけましょう.

  3. 前回の復習

    乱数について,実際の演習問題を通して理解していくことを行いました.乱数を発生させる際に,どのような乱数を発生させるかについては剰余の上手な利用が不可欠でした.剰余算についての理解も,これからどんどん進めて行ってください.

  4. 式と文

    これまで, printf() 文とかの言葉を使ってきましたが,この節のところをよく読んで,文の意味も理解してください.今回からは if 文が登場します.

    なお,教科書のp.47の文並びやブロックにある例は,それだけでは動作しませんので注意してください.このままエディタに打ち込んでコンパイルすると,当然ですが,変数 a などが定義されていないので,エラーとなります.

    中括弧で囲まれた部分を「ブロック」と言いますが,ブロックの中に書かれる式や文は字下げ(インデント)されますので,ご注意ください.

  5. if

    • 教科書の補足

      今回は変数などの値に従って次の処理が変わる「分岐」を扱います.分岐させるための判断として,今回は関係演算子(比較演算子)と等価演算子について学習します.値が大きい,小さい,等しい,等しくないなどの演算を行って,その結果に応じて処理が変わります.

      教科書p.49のリスト3_1ですが,肝心の if 文のところが変則的な表現になっています.

          if(a % 2)
          {
              printf("Odd number\n");
          }
      

      これは例題としてはあまりふさわしくないようです.本来であれば次のように書くべきです.

          if(a % 2 != 0)
          {
              printf("Odd number\n");
          }
      

      もしくは,

          if(a % 2 == 1)
          {
              printf("Odd number\n");
          }
      

      関係演算子や等価演算子などの演算は,結果がブール値で返ってきます.すなわち,「真」もしくは「偽」です.TrueもしくはFalseということなのですが,その値は処理系によって異なっているものの,偽の場合に0という数値を返すことはほとんどの言語で同じです.なので,動作的には正しく行われるものの,明示的に期待する結果を判断していないので,おすすめしません.

      また,教科書p.49の中頃に,以下のような記述があります.

      なお,本書では if 文の文をいつでもブロックの形で書くこととする.

      実は if 文はその式が1行だけなら中括弧無しでも動作します.

          if(a>2)
          {
              printf("OK\n");
          }
      

      のような処理は

          if(a>2)
              printf("OK\n");
      

      でも動作します.ただし,文が2行以上になる場合には,必ず中括弧が必要です.さらに,中括弧の位置ですが,教科書と違う以下のような位置で書くこともよく行われています.

          if(a>2){
              printf("OK\n");
          }
      

      この授業ではどちらでも構わないこととします.個人的には上の書き方の方が好きですが,今後は教科書の方式に統一して例題は作成します.

      ところで,教科書のp.50にあるリスト3_2ですが,関数 main() の後の中括弧の位置がこれまでと違っています.

      これまでの例
      int main(void)
      {
      

      リスト3_2
      int main(void){
      

      どちらにあっても動作に影響は無いのですが,3_2はたまたま間違ってこうなっていると思われますので,気にしないでこれまで通りの位置で書いていきましょう.

    • 多重の if

      if 文の中に if 文を入れることも可能です.次週以降で出てくる論理演算子を使用すれば回避できる場合もありますが,使用することも多いので,少し練習しておきましょう.

      #include <stdio.h>
      #include <stdlib.h>
      #include <time.h>
      
      int main(void)
      {
          srand((unsigned) time(NULL));
          
          int num = rand() % 21 - 10;
          
          printf("Random number: %d\n", num);
          
          if(num<=4)
          {
              if(num>=-4)
              {
                  printf("Its absolute value is less than 5.\n");
              }
          }
          
          return 0;
      }
      

      これを実行すると,例えば,以下のようになります.

      Random number: -2
      Its absolute value is less than 5.
      

      上の例では,処理以外にもインデントのやり方にも注意してください.ブロックが出てくるたびにインデントのTABが1個増えます.

  6. if-else

    今回学習するのは教科書p.51にある if-else 文です.使い方はリスト3_3などの例題を見てもらいたいのですが,前回出てきた if 文の拡張にあたります.しかし,実は使う上で意味が大きく異なりますので,注意してください.まずは,基本的に理解しておかなければならない目的の部分です.

    if 文は,何かの条件に合致した時に特定の処理を行うけれども,合致しなかった場合には何もしない,というのが使用の条件です.一方, if-else 文は必ず何かの処理を行うのだけれども,行うにあたって場合分けが必要なときに使用します.以下に単純な例を示します.

    • 発生させた乱数が偶数だったらEvenと表示する.

      #include <stdio.h>
      #include <stdlib.h>
      #include <time.h>
      
      int main(void)
      {
          srand((unsigned) time(NULL));
          
          int num = rand() % 90 + 10;
          
          printf("Random number: %d\n", num);
          
          if(num%2==0)
          {
              printf("Even\n");
          }
          
          return 0;
      }
      

    • 発生させた乱数が偶数か奇数かを表示する.

      #include <stdio.h>
      #include <stdlib.h>
      #include <time.h>
      
      int main(void)
      {
          srand((unsigned) time(NULL));
          
          int num = rand() % 90 + 10;
          
          printf("Random number: %d\n", num);
          
          if(num%2==0)
          {
              printf("Even\n");
          }
          else
          {
              printf("Odd\n");
          }
          
          return 0;
      }
      

      上のプログラムは,下のように書くことも可能ではあります.

      
      #include <stdio.h>
      #include <stdlib.h>
      #include <time.h>
      
      int main(void)
      {
          srand((unsigned) time(NULL));
          
          int num = rand() % 90 + 10;
          
          printf("Random number: %d\n", num);
          
          if(num%2==0)
          {
              printf("Even\n");
          }
      
          if(num%2==1)
          {
              printf("Odd\n");
          }
          
          return 0;
      }
      


      上のような if 文を2回書くプログラムは動作間違っていませんが,推奨しません.今は場合が2つだけで単純ですが,いくつもの場合があったり,条件分けが複雑だったりした時に,何らかの「抜け落ち」が発生する可能性があります.とにかく,何かの処理をするのであれば,保険として else をつけてください.
    • 入れ子の if-else

      教科書p.54のリスト3_5のように, if 文同様, if-else 文も入れ子にできます.

    • else if

      条件が3つ以上になると,教科書p.55のリスト3_6のように else if を使う場合があります.これも演習で確認しましょう.

  7. 実習

    実習の演習問題は予習用の部分はすでに見えますのでしっかり予習してください.

  8. 次回の予習範囲

    教科書のp.55まで予習をしてきてください.

  9. 宿題

    宿題は基本的に月曜日の18:00公開です.締切りは翌週の月曜10:00です.


目次ページに戻る