計算プログラムを例として, Linux(unix)環境でのC言語プログラミングの作業方法を把握しよう.
まずは,マウス操作によりアプリケーション「端末」を開こう. そして,その端末内でキーボード操作により, 次のようなコマンド(命令)を入力しよう:
$ cd # ホームディレクトリへ移動 $ mkdir p-1023 # 本日の作業用ディレクトリを作成 $ cd p-1023 # 作業用ディレクトリへ移動
ここで,行頭の記号「$」はプロンプト(入力促進)です. キーボードによる unix コマンドの入力が求められています. プロンプト記号を入力する必要はありません.
また,記号「#」から行末まではコメント(説明文)です. これも入力不要です.
これで,今回作成する複数のファイルを ひとつのディレクトリにまとめておくことになる. 次回以降も同様に作業しよう.
ディレクトリやファイルの操作では, 次のコマンドもおぼえておこう:
$ ls # ファイルの確認(どんなファイルがあるか?) $ pwd # カレントディレクトリの確認(今,どこにいるか?)
C言語プログラムの作成から実行までの手順は次の通り:
エディタを利用し,ソースコード(プログラムの内容)を記述し, ソースファイル(拡張子「.c」)として保存する:
$ gedit ソース.c & # gedit & の代わりに nano とかでも OK
ソースファイルは人間が読み書きするためだけのものであり, このままではまだ,コンピュータが実行できる状態ではない.
コンパイラを利用し,ソースファイルを 実行形式(プログラムファイル)に変換する:
$ cc ソース.c -o プログラム
これで,実行可能な状態のプログラムファイルが生成される.
もし,ソースコード内に明らかな間違いがあった場合には, エラーメッセージが表示される. この場合,手順1(編集作業)へ戻り, デバッグ(間違いを修正)しよう.
ディレクトリパス名とプログラムファイル名とを指定して実行する:
$ ./プログラム
もし,実行結果が期待通りでなければ, また手順1に戻り,デバッグを繰り返そう.
割り算を計算するプログラムを例として, C言語プログラムの開発作業を体験しよう. 単純なプログラムから開始し, 徐々に機能を向上させて行きます.
ソースファイルを編集:
$ 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 しか計算できない? しかも,計算結果が間違っている? プログラムがおバカ,というか,プログラマが...
プログラマが働く(そして間違える...)のではなく, コンピュータを働かせよう.
... int main(void) { printf("12/3 = %d\n", 12/3); // %dは12/3の計算結果に置き換わる return (0); }
$ cc ... $ ./div 12/3 = 4
正しく計算できた.
数式内の数値を色々と変更し, 正しく計算できることを確認しよう.
でも,変更しなければならない部分が2箇所もあり面倒だよね...
プログラムを効率良く(手間なく)書こう.
変数(メモリ)を使えば, 変更すべき箇所を少なくできる. そして,プログラマの間違いも少なくできる.
... int main(void) { int x = 12, y = 3; // 数値を色々と変更してみよう int z; // 計算結果を入れるための変数.プログラム作成時には数値は未定. z = x/y; printf("%d/%d = %d\n", x, y, z); return (0); }
...
はい,数値の変更は1箇所だけにできた.
しかし,別の数式を計算するために,いちいちソースを変更し, コンパイルもやり直す必要がある. これはまだまだ面倒くさい...
プログラムに柔軟性を与えよう. 何度も作り直さなくても,様々な計算に利用できるように.
... int main(void) { int x, y; // 作成時には数値は未定 int z; printf("2個の整数値 > "); // プロンプトを表示する scanf("%d %d", &x, &y); // 実行時に数値を入力する z = x/y; printf(...); return (0); }
...
$ ./div 2個の整数値 > 12 3 # x と y の値を空白で区切って入力 12/3 = 4 $ ./div 2個の整数値 > 20 4 20/4 = 5 ...
これでどんな割り算でも計算できるようになった?
本当に? 例えば,y にゼロを入力するとどうなるか? その後の終了状態 $? の値は?
動いていたシステムが突然動かなくなってしまうと,ユーザはとても困ります...
エラー発生を事前に察知して,ディザスタ(災害・惨事)を防ごう.
... int main(void) { int x, y; int z; printf("2個の整数値 > "); scanf("%d %d", &x, &y); if (y == 0) { // y がゼロの場合...(y = 0 ではなく y == 0 ね) printf("ゼロでは割れません.\n"); // 割らない } else { z = x/y; // ゼロ以外なら割る printf("%d/%d = %d\n", x, y, z); } return (0); }
...
色々な数値を入力して,実験を繰り返そう.
あーでも,プログラムを何度も実行しなおすのも面倒くさいぞ...
反復(繰り返し)
... 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] でプログラムを強制終了しよう.
それに,終了メッセージが表示されないぞ? どこが変?
... int main(void) { int x, y; int z; while (1) { printf("2個の整数値 > "); if (scanf("%d %d", &x, &y) == EOF) break; // キー操作 [Ctrl]+[D] で入力を終了し,break で繰り返しを終了 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]
おつかれさまでした.
これで,何とか実用的なプログラムとしての形が整った?
割り算プログラム div.c の逆バージョンを考えよう. 人間が出題しコンピュータに計算させるのではなく, コンピュータが出題し人間が計算する... クイズゲームのような計算練習ソフトになりそうです.
次の実行例のような,男子小学生向け エデュテイメントソフト「💩計算ドリル」を開発してみよう. ( 元ネタ)
$ 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); }
上級者は,機能を追加してみよう. たとえば,成績(正答数,誤答数,正答率,など)の表示機能とか?
もし余裕があれば,取り組んでみよう.
割り算プログラム div.c を改造し, コマンドライン上で数値を指定できるようにしてみよう. つまり,プログラムの実行途中ではなく, 実行開始時に数値を指定できるようにする.
ここでは 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言語で作られています.
質問 Q1〜Q2 に回答し,電子メールで提出せよ.
メール設定変更には,メール確認(Microsoft365 Outlook)のページ上で設定ボタン⚙を探してください.