数値変数・数式・書式付き入出力の適切な使い方を理解しよう. そして,超単純な数値データ処理プログラムを作成してみよう.
まずは,作業用ディレクトリを準備しよう:
$ cd $ mkdir c-0507 $ cd c-0507 # または $ cd !$
前回は Vim を使ってみましたが,気に入らない場合, 別のエディタを使って構いません.
選択肢:vim,nano,emacs,gedit,等...
使用方法:
$ vim ソース.c $ nano ソース.c $ emacs ソース.c $ gedit ファイル.c & # GUIアプリの場合「&」が必要
今後の作業を効率化するため, ソースファイルのテンプレートを ホームディレクトリ等に作成しておこう:
$ vim ~/tmpl.c # エディタは vim 以外でも OK # 「~/」はホームディレクトリを意味する特殊記号
#include <stdio.h> int main(void) { return (0); }
ソースファイルを新規に作成する際, このテンプレートをコピーして使えば良い:
$ cp ~/tmpl.c 新ソース.c # ファイルのコピー $ vim 新ソース.c ...
これで毎回,同じようなコード (#include とか main とか)を 書き直す手間を節約できる.
テンプレートを元にして,ソースファイルを編集:
$ cp ~/tmpl.c hello.c $ vim 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 を作成してみよう.
前処理部のソースコード断片:
#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 としましょう:
#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〜Q6 に回答し,電子メールで提出せよ.