計算プログラムを例として, Linux(unix)環境でのC言語プログラミングの作業方法を把握しよう.
まずは,マウス操作によりアプリケーション「端末」を開こう. そして,その端末内でキーボード操作により, 次のようなコマンド(命令)を入力しよう:
$ cd # ホームディレクトリへ移動 $ mkdir c-0425 # 本日の作業用ディレクトリを作成 $ cd c-0425 # 作業用ディレクトリへ移動
行頭の記号「$」はプロンプト(入力促進)の表示であり, この記号は入力しないこと. また,記号「#」から行末まではコメント(説明文)であり, 入力する必要はない. なお,unix 用語「ディレクトリ」は Windows 用語「フォルダ」とほぼ同じ意味をもつ.
これで,今回作成する複数のファイルを ひとつのディレクトリにまとめておくことになる. 次回以降も同様に作業して行こう.
ディレクトリやファイルの操作では, 次のコマンドもおぼえておこう:
$ ls # ファイルの確認(どんなファイルがあるか?) $ pwd # カレントディレクトリの確認(今,どこを見ているか?)
C言語プログラムの作成から実行までの手順は次の通り:
エディタを利用し,ソースコード(プログラムの内容)を記述し, ソースファイル(拡張子「.c」)として保存する:
$ gedit ソース.c & # emacs や leafpad でも OK
ソースファイルは人間が読み書きするためのものであり, このままではまだ,コンピュータが実行することはできない.
コンパイラを利用し,ソースファイルを 実行形式(プログラムファイル)へ変換する:
$ cc ソース.c -o プログラム
これで,実行可能なプログラムファイルが生成される.
しかし,ソースコードに間違いがあった場合, エラーメッセージが表示される. この場合,編集作業へ戻り, デバッグ(間違いを修正)しよう.
プログラムファイル名を指定して実行する:
$ ./プログラム
もし,実行結果が期待通りでなければ, さらにデバッグしよう.
割り算を計算するプログラムを例として, プログラム開発の作業を体験しよう. 単純なプログラムから開始し, 徐々に機能を向上させて行きます.
ソースファイルを編集:
$ gedit div.c &
int main(void) { return (0); // 行頭の空白は[Tab]キーね } // 記号列「//」から行末まではコメントなので入力不要だよ
編集が終わったら「保存」をお忘れなく.
そしてコンパイル:
$ cc div.c -o div # 拡張子.c の有無に注意!!
エラーが発生したら,編集に戻るんですよ.
エラーがなければ,実行:
$ ./div
...何も起きないのですが?
...はい,何もしていないので.
このプログラムの実行直後に, 次のコマンドを実行してみよう:
$ echo $? # 直前のプログラムの終了状態 $? を表示
戻り値(return (N) の数値 N)を色々と変更し, 実行結果を確かめてみよう.
ソースを改造:
#include <stdio.h> // printf() を使う場合に必要 int main(void) { printf("12/3 = 5\n"); // 数式を表示.間違いはそのままに... // \n は改行記号 return (0); }
保存 → コンパイル → 実行:
$ cc ... $ ./div 12/3 = 5
何か表示されたが,12/3 しか計算できない? しかも,計算結果が間違っている? プログラムがおバカ,というか,プログラマが...
プログラムは思い通りには動かない. 書いた通りに動く.
コンピュータは間違わない. プログラマが間違えるんだ.
#include <stdio.h> int main(void) { printf("12/3 = %d\n", 12/3); // %dは12/3の計算結果に置き換わる return (0); }
$ cc ... $ ./div 12/3 = 4
正しく計算できた.
数式内の数値を色々と変更し, 正しく計算できることを確認しよう.
でも,変更しなければならない部分が2箇所もあり面倒だよね...
変数(メモリ)を使えば, 変更すべき箇所を少なくできる.
#include <stdio.h> int main(void) { int x = 12, y = 3; // 数値を色々と変更してみよう int z; // 計算結果を入れるための変数.プログラム作成時には数値は未定. z = x/y; printf("%d/%d = %d\n", x, y, z); return (0); }
...
はい,数値の変更は1箇所だけにできた.
しかし,別の数式を計算するために,いちいちソースを変更し, コンパイルもやり直す必要がある. これはまだまだ面倒くさい...
#include <stdio.h> int main(void) { int x, y; // 作成時には未定 int z; printf("2個の整数値 > "); // プロンプトを表示する scanf("%d %d", &x, &y); // 実行時に数値を入力する z = x/y; printf("%d/%d = %d\n", x, y, z); return (0); }
...
$ ./div 2個の整数値 > 12 3 # x と y の値を空白で区切って入力 12/3 = 4 $ ./div 2個の整数値 > 20 4 20/4 = 5 ...
これでどんな割り算でも計算できるようになった? しかし,y にゼロを入力するとどうなるか? その後の終了状態は?
#include <stdio.h> int main(void) { int x, y; int z; printf("2個の整数値 > "); scanf("%d %d", &x, &y); if (y == 0) { // y がゼロの場合... printf("ゼロでは割れません.\n"); // 割らない } else { z = x/y; // ゼロ以外なら割る printf("%d/%d = %d\n", x, y, z); } return (0); }
...
色々な数値で実験しよう.
あーでも,プログラムを何度も実行しなおすのは面倒くさいぞ...
#include <stdio.h> int main(void) { int x, y; int z; while (1) { // 繰り返す printf("2個の整数値 > "); scanf("%d %d", &x, &y); if (y == 0) { printf("ゼロでは割れません.\n"); } else { z = x/y; printf("%d/%d = %d\n", x, y, z); } } printf("\nおつかれさまでした.\n"); // 終了メッセージを表示 return (0); }
...
繰り返しが止まらない... とりあえず,キー操作 [Ctrl]+[C] でプログラムを強制終了しよう.
それに,終了メッセージが表示されないぞ.
#include <stdio.h> int main(void) { int x, y; int z; while (1) { printf("2個の整数値 > "); if (scanf("%d %d", &x, &y) == EOF) break; // キー操作 [Ctrl]+[D] で繰り返しを終了 if (y == 0) { printf("ゼロでは割れません.\n"); } else { z = x/y; printf("%d/%d = %d\n", x, y, z); } } printf("\nおつかれさまでした.\n"); return (0); }
...
$ ./div
2個の整数値 > 20 4
20/4 = 5
2個の整数値 > [Ctrl]+[D]
おつかれさまでした.
これで,何とか実用的なプログラムとしての形が整った?
割り算プログラムの逆バージョンを考えよう. 人間が出題しコンピュータに計算させるのではなく, コンピュータが出題し人間が計算する... クイズゲームのような計算練習ソフトになりそうです.
というわけで,男子小学生向け エデュテイメントソフト「計算ドリル」を開発してみよう. ( 元ネタ)
$ gedit drill.c & $ cc drill.c -o drill $ ./drill うんこ計算ドリル ♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪ 84 個のうんこをもらいました. 7 人で山分けしましょう. 一人分は何個ですか? > 7 ☓ :正解は 12 です. ♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪ 78 個のうんこをもらいました. 6 人で山分けしましょう. 一人分は何個ですか? > 13 ◯ ♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪ . . . おしまい.
#include <stdio.h> #include <stdlib.h> //rand() を使うために必要 int main(void) { int x, y, z; // 問題の数値 z = x/y; int a; // ユーザが入力する答案の数値 printf("うんこ計算ドリル\n"); // タイトルを表示 while (1) { x = rand()%100 + 1; // 1〜100の乱数を設定 y = rand()%10 + 1; // 1〜10の乱数を設定 printf("♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪\n"); printf("%d 個のうんこをもらいました.\n", x); printf("%d 人で山分けしましょう.\n", y); printf("一人分は何個ですか? > "); // ====== 適切なコードを追加し,プログラムを完成しなさい ====== ... // 答案を入力 ... // 正解を計算 ... // 正/誤を判定 // ====== ここまで ====== } printf("\nおしまい.\n"); return (0); }
上級者は,機能を追加してみよう. たとえば,成績(正答数,誤答数,正答率,など)の表示機能とか?
コマンドライン上で数値を指定できるようにしてみよう. つまり,プログラムの実行途中ではなく, 実行開始時に数値を指定できるようにする.
ここでは Step 3 のソースコードを元にして改造しよう:
#include <stdio.h> #include <stdlib.h> // atoi() に必要 int main(int argc, char *argv[]) { int x, y; int z; if (argc != 3) return (1); // 引数不足等の場合,終了 x = atoi(argv[1]); // 引数1 を x に代入 y = atoi(argv[2]); // 引数2 を y に代入 if (y == 0) return (1); // ゼロ割りを回避 z = x/y; printf("%d/%d = %d\n", x, y, z); return (0); }
コマンドラインに指定されたデータは, 変数 argv[番号] にセットされる. ただし,そのデータは文字列(数字列)なので, 関数 atoi( ) で数値に変換した.
実行例:
$ ./div 24 8 24/8 = 3 $ ./div 32 16 32/16 = 2
これって結局,unix コマンドを自分で作った,ということだよね? そだねー. 実際,unix コマンドのほとんどはC言語で作られています.