基礎プログラミング演習(1)
ご無沙汰してます。 ややあって、友人のプログラミング初心者2人とプログラミング勉強お泊まり会をしましたので、そのレポート的なものを残しておきます。
条件など
- 2人はプログラミング初心者
- 入門書の前半くらいまで読みかけ
- 使用言語は、一人がC++、もう一人がC#
- 何から書いたらいいのかわからないから、とにかく書いてみたいとのこと
- 夜22時開始、朝までやれるだけやってみることにしました
進行
簡単に講義
- 言語の分類(オブジェクト指向言語、関数型言語など)
- 実行方式(コンパイル言語、スクリプト言語、中間形式出力)
- 基本的なデータ型の紹介(int, float, char, bool, ポインタ, string, DateTime, Array, List……)
- 構文要素(文、式、演算子、変数、ブロック、関数)
- 駆け足進行でしたが、ここまでで1時間ほど経過
演習問題(1)
- 「BMI値を計算するCUIアプリを作ってみよう」という定番ネタを出題
- 手書きで要件を箇条書きして説明、ハイ作ってと渡しました
- 書いているところに逐次突っ込みを入れる、助け舟を出すなど適当に進行しました
- 書き方を調べながらのため、2, 3時間ほど経過
- C#のほうは問題なかったものの、私がC++を全くわからないため、実質的にはCで書いてもらうことになりました
- クラス等が必要になるまでには勉強しておきます
- 詰まりポイントは、主に型変換の類が多かった模様です
- 「入力した文字列を整数に変換しなければいけないのですが?」
- Cではscanfなので問題なし。C#ではConvert.ToInt32を解説しました
- 「センチメートルで入力したのに計算はメートル単位です、どうしたらいいのでしょうか?」
double 身長_メートル = 身長/100;// 何故か小数点以下が切り捨てられてしまう
- キャストを噛ませないとint型で割り算してしまいます
- 「入力した文字列を整数に変換しなければいけないのですが?」
発展問題(1-1, 1-2)
- 1-1「BMI値に応じて『やせ』『普通』『肥満』と表示しよう」
- 1-2「数値以外が入力されたり、0や負の値が入力されたら、エラーと表示して再入力させよう」
- 前者が条件分岐、後者がループ(while文)の演習なのは明白ですね
- 分岐はすんなり解くものの、ループで二人とも頭を抱えていました
- 「そもそも変な文字を入力したら、エラーになったりするのですが?」
- Cでscanf("%d\n", &buf)を使うとここでハマります
- C#だとint.Parseを使っているとエラーになります
- 「エラーなら再入力、成功したら終了ってどう書けばいいのでしょうか?」
- whileやbreakを調べてみましょう
- 「そもそも変な文字を入力したら、エラーになったりするのですが?」
- プログラミング言語で書き始める前に、日本語で書いてもらったり、フローチャート風の図を描いてもらったり、とにかく手を動かして考えるのに重点をおいて進行しました
- この時点で夜が明けそうになる(午前6時)ので、いったん就寝しました
- 空いた時間で、私のほうでお手本プログラムを用意していました
- 手続き的なべた書きで「とりあえず動く」プログラムができたところで、「関数を使って整理するとこんな感じ」とざっと解説して終了。お疲れ様でした。
問題文全文
演習問題1
- コマンドラインで動くコンソールアプリ
- exeファイルを実行すると「身長は?」と表示される
- 整数(単位はセンチメートル)を入力して決定すると「体重は?」と表示される
- 整数(単位はキログラム)を入力して決定すると「あなたのBMIはXXです」(XXは計算したBMI値)と表示され、アプリケーションが終了する
- 注意点として、BMI値は小数点以下まで計算すること
演習問題1-1
演習問題1に加えて、以下の要件を満たせ
演習問題1-2
演習問題1-1に加えて、以下の要件を満たせ
- 身長と体重を入力する際に、下記条件に当てはまらない場合「エラー。0より大きい整数を入力してください」と表示して、再度入力をさせること
- もし体重の入力でエラーになったとしても、身長の値の入力には戻らず、体重の値を入力すればよいようにする
条件
- 0より大きい整数であること
- 例えば、0, -1, 50.5, aaaaaaなどはすべてエラー
作成したお手本プログラム(C言語)
#include <stdio.h> #include <stdlib.h> #include <limits.h> #include <stdbool.h> #include <string.h> // struct that express int or none value typedef struct { bool isSome; int value; } IntOrNone; // create some int value IntOrNone someInt(int v){ IntOrNone r = { true, v }; return r; } // create none int value IntOrNone noneInt(){ IntOrNone r = { false, 0 }; return r; } // convert string to int IntOrNone tryParseInt(char* s){ char *end; long result = strtol(s, &end, 10); if(*end != '\0') return noneInt(); if(result > INT_MAX || result < INT_MIN) return noneInt(); return someInt((int)result); } // validate input value IntOrNone validate(char* s){ IntOrNone x = tryParseInt(s); if(!x.isSome) return noneInt(); if(!(x.value > 0)) return noneInt(); return x; } // compute bmi value double computeBmi(int h, int w){ double hMeter = ((double)h)/100; return w/(hMeter*hMeter); } // define bmi type typedef enum { Fat, Slim, Normal } BmiType; // get string of bmi type char* getBmiTypeName(BmiType t){ switch(t){ case Fat: return "肥満"; case Slim: return "痩せ"; default: return "普通"; } } // check bmi type by bmi value BmiType checkBmiType(double bmi){ if(bmi < 18.5) return Slim; if(bmi >= 25) return Fat; return Normal; } // write string to console void write(char* m){ printf("%s", m); } // read string by console char* read(char* buf, int max){ if(fgets(buf, max, stdin) == NULL){ return ""; } if(strchr(buf, '\0') != NULL){ buf[strlen(buf) - 1] = '\0'; }else{ while(getchar() != '\n'); } return buf; } // get correct integer value int getInput(){ char buf[100]; while(true){ IntOrNone x = validate(read(buf, 100)); if(x.isSome) return x.value; write("error. 0より大きい整数を入力して下さい\n"); } } int main(){ write("身長は?\n"); int h = getInput(); write("体重は?\n"); int w = getInput(); double bmi = computeBmi(h, w); char buf[100]; sprintf(buf, "あなたのBMIは%fです\n", bmi); write(buf); sprintf(buf, "あなたは%s体型です\n", getBmiTypeName(checkBmiType(bmi))); write(buf); }
- CでもOption
が使いたかったのです - 学生の頃以来の、数年ぶりに書いたCですが、標準入出力と文字列処理がやはり面倒でした