数値変数・数式・書式付き入出力の適切な使い方を理解しよう. そして,超単純な数値データ処理プログラムを作成してみよう.
まずは,作業用ディレクトリを準備しよう:
$ cd # ホームディレクトリへ移動(省略OKの場合もある) $ mkdir p-1029 # 本日の作業用ディレクトリを作成 $ cd p-1029 # 作業用ディレクトリへ移動 # または $ cd !$ # !$ は直前のコマンドの引数 p-1029 に置き換わる
今後の作業を効率化するため, ソースファイルのテンプレートを ホームディレクトリ等に作成しておこう:
$ gedit ~/tmpl.c & # エディタは gedit 以外でも OK # 「~/」はホームディレクトリを意味する特殊記号
#include <stdio.h>
int main(void)
{
return (0);
}
ソースファイルを新規に作成する際, このテンプレートをコピーして使えば良い:
$ cp ~/tmpl.c 新ソース.c # ファイルのコピー $ gedit 新ソース.c & ...
これで毎回,同じようなコード (#include とか main とか)を 書き直す手間を節約できる.
テンプレートを元にして,ソースファイルを編集:
$ cp ~/tmpl.c hello.c $ gedit hello.c &
#include <stdio.h>
int main(void)
{
printf("Hello World\n"); // 「Hello World」と表示
return (0);
}
ソースをコンパイルして,実行形式(プログラム)を生成:
$ cc hello.c -o hello
実行形式が生成されたか?確認:
$ ls hello hello.c
プログラムを実行:
$ ./hello # プログラムを実行 Hello World $
データ処理プログラムの段取りの基本形を理解しておきましょう. (データ処理に限らず,大抵のプログラムは3段階から構成されます.)
では,3段構成を意識しながら, 具体例として掛け算プログラム mul.c を作成してみよう.
$ cp ~/tmpl.c mul.c $ gedit mul.c &
前処理部のソースコード断片:
#include <stdio.h> // 入力関数 scanf() の宣言を取り込み
// 「後で scanf() を使うよー」とヘッダファイル stdio.h 内に書いてある
// ...前処理部の準備
int main(void)
{
int num; // 整数型の変数 num を宣言
// 「後で num を使うよ,整数を代入できるよー」
double val; // 実数型の変数 val を宣言
// 「後で val を使うよ,実数を代入できるよー」
printf("整数と実数を入力せよ >"); // 入力プロンプトを表示
scanf("%d %lf", &num, &val);
// 「最初に %d で整数,次に空白,最後に %lf で実数,
// というパターンでキーボードから入力してねー」
// 「変数 num に整数,val に実数が格納されるよー」
// 変数名の前「&」の付け忘れに注意!!
// 本処理部
... // この先は次のステップで作成
}
基礎知識:
本処理部のソースコード断片:
...
int main(void)
{
double total; // 「後で計算結果を代入するよ」
// ...本処理部の準備
... // 前処理部
total = num*val;
// かけ算 num*val を計算し,計算結果を変数 total へ代入してね.
...
}
基礎知識:
なお,C言語の世界(コンピュータの内部)では, 整数データと実数データとは明確に区別されています. たとえば,整数 123 と実数 1.23×102 は互いに別物です. 数値的には「ほぼ等しい」かもしれないが, 完全に一致するとは限りません.
また,取り扱い可能な数値の範囲に制限があります. 計算結果のオーバーフロー等に注意が必要です.
後処理部のソースコード断片:
#include <stdio.h> // 出力関数 printf() の宣言を取り込み
// 「後で printf() を使うよー」とヘッダファイル stdio.h 内に書いてある
// ... 後処理部の準備
int main(void)
{
... // 前処理部,本処理部
printf("%d * %f = %f\n", num, val, total);
// 「文字や数値を端末画面に表示してねー」
// 「%d は整数 num,%f は実数 val とtotal の値に置き換わるよー」
return (0); // プログラムを終了
}
基礎知識:
はい,ではこのプログラムをコンパイル・実行しましょう:
$ cc mul.c -o mul $ ./mul ...
正しく掛け算できたでしょうか?
整数型(int型)データの1個あたりの情報量は, 4 byte(16進数8桁)=32 bit(2進数32桁)であり, 表現可能な数値の範囲は 0 〜 232ー1 ≒ 約40億となります. ただし通常は,負の数も使うので, 範囲はー約20億 〜 +約20億となっています.
ソースファイルを int.c としましょう:
$ cp mul.c int.c
#include <stdio.h>
int main(void)
{
int x, y, z; // 整数型の変数 x,y,z の宣言
while (1) { // 繰り返し
printf("整数2個 > ");
scanf("%d %d", &x, &y); // 入力
z = x * y; // 計算(かけ算)
printf("%d * %d = %d\n", x, y, z); // 出力
}
return (0);
}
コンパイルと実行:
$ cc int.c -o int
$ ./int
整数2個 > 35 100
35 * 100 = 3500 # そだねー
整数2個 > 3500 1000000
3500 * 1000000 = -794967296 # えっ??
# 正解は 35億では?しかも,マイナスって何だー?
整数2個 > [Ctrl]+[C] # 強制終了
はい,今,オーバーフローが発生しました. 「コンピュータは正確」と思っていた人は残念でした. コンピュータの能力には限界があります. 能力の範囲内であれば正確です.
実数型(double型)のデータ1個あたりの情報量は 8 byte, 数値範囲は±約1.0×10±308, 有効数字は15桁となっています.
ソースファイルを double.c としましょう:
#include <stdio.h>
int main(void)
{
double x, y, z; // 実数型の変数 x,y,z の宣言
while (1) {
printf("実数2個 > ");
scanf("%lf %lf", &x, &y); // 入力
z = x / y; // 計算(わり算)
printf("%f / %f = %f\n", x, y, z); // 出力
}
return (0);
}
$ cc double.c -o double $ ./double 実数2個 > 1 3 1.000000 / 3.000000 = 0.333333 実数2個 > 2.0 1.41421356 2.000000 / 1.414214 = 1.414214 実数2個 > 1 0 1.000000 / 0.000000 = inf # inf は infinity...無限ね 実数2個 > 0 0 0.000000 / 0.000000 = -nan # nan って何?not a number...不定値,非数 ...
(型の指定)
(幅の指定)
実験:書式指定をわざと間違えてみよう. ソースファイルは fmt.c:
#include <stdio.h>
int main(void)
{
int x = 123;
double y = 123.45;
printf("正:\n");
printf("x = %d\n", x);
printf("y = %f\n", y);
printf("誤:\n");
printf("x = %f\n", x); // 整数型は %d のハズ
printf("y = %d\n", y); // 実数型は %f のハズ
return (0);
}
コンパイルすると,どうなりますか?
実行結果は,どうなりましたか?
さらに実行を繰り返すと?
変数の値を使用して何かを計算する場合, 事前に初期化(初期値を代入 or 入力)しておく必要があります.
実験:変数をわざと初期化せずに使ってみよう.var.c:
#include <stdio.h>
int main(void)
{
// int x=1, y=2, z=3; // 初期化すると...
int x, y, z; // 初期化しないと...
printf("%d %d %d\n", x, y, z); // どんな値?
return (0);
}
実行結果はどうなりましたか? 何度も繰り返すと?
ここまでの知識を使って, 整数を 10進数(decimal)として入力すると 16進数(hexadecimal)に変換して出力するプログラム d2x.c を独自に作成しよう. 本日の課題の重要部分です.
実行例:
$ ./d2x
10進数 > 255
16進数 = FF
10進数 > 16
16進数 = 10
...
10進数 > [Ctrl]+[C] # 強制終了
$
余裕があれば,タスク7の逆バージョン... 整数を 16進数として入力すると 10進数に変換して出力するプログラム x2d.c も作成しよう.
質問 Q1〜Q4 に回答し,電子メールで提出せよ.