基本的なデータ処理

数値変数・数式・書式付き入出力の適切な使い方を理解しよう. そして,単純な数値データ処理プログラムを作成してみよう.

教科書の該当範囲:第2章〜第5章

実習の準備

いつもの通り,作業用ディレクトリを準備しよう:

$  cd
$  mkdir  c-0509
$  cd  c-0509

データ処理の手順のまとめ

データ処理プログラムの段取りの基本形は次の通り:

  1. 前処理:変数の宣言,データの入力,等
  2. 書式付き入力 scanf() を利用して, キーボードからデータを入力し, 入力されたデータを変数に格納する. なお,変数の利用には事前準備が必要であり, ソースの先頭付近で型と名前を宣言しておく.

    コード例:

    #include <stdio.h>	// scanf() に必要
    int main(void)
    {
    	int	num;	// 整数型の変数 num を宣言
    		// 「後で num を使うよ,整数を代入できるよ」
    	double	val;	// 実数型の変数 val を宣言
    		// 「後で val を使うよ,実数を代入できるよ」
    	...
    	scanf("%d  %lf", &num, &val);
    		// 最初に %d で整数,次に空白,最後に %lf で実数,
    		// というパターンでキーボードから入力してね.
    		// 変数 num に整数,val に実数が格納されるよ.
    		// 変数名の前「&」の付け忘れに注意!!
    	...
    }
    
  3. 本処理:計算等
  4. 数式等を利用して,目的のデータ処理を実行する.

    コード例:

    ...
    int main(void)
    {
    	double	total;
    	...
    	total = num*val;
    		// かけ算 num*val を計算し,計算結果を変数 total へ代入してね.
    	...
    }
    

    計算結果のデータにも型があることに注意しよう.

  5. 後処理:処理結果の出力等
  6. 書式付き出力 printf() を利用し, 端末画面に計算結果等を表示する.

    コード例:

    #include <stdio.h>	// printf() に必要
    int main(void)
    {
    	...
    	printf("%d * %f = %f\n", num, val, total);
    		// 文字や数値を端末画面に表示してね.
    		// %d は整数 num,%f は実数 val とtotal の値に置き換わるよ.
    	...
    }
    

    printf() と scanf() の書式について, %f と %lf のように, 微妙な違いがあることに注意しよう.

第2回の授業で作ったプログラムは, ほぼすべて,このパターンだった.

なお,C言語の世界では, 整数データと実数データとは明確に区別されている. たとえば,整数 123 と実数 1.23×102 は互いに別物となる. 数値的に,ほぼ等しいかもしれないが,完全に一致するとは限らない.

また,取り扱い可能な数値の範囲に制限がある. 計算結果のオーバーフロー等に注意しよう.


整数データの処理

int型の整数データ1個あたりの情報量は, 4 byte(16進数8桁)=32 bit(2進数32桁)であり, 表現可能な数値の範囲は 0 〜 232ー1 ≒ 約40億となる. ただし通常は,負数も使うので,範囲はー約20億 〜 +約20億となる.

int は integer(整数)を意味する.

ソースを編集:

$  vim  int.c		# エディタは何でも OK
#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	# えっ??

整数2個 > [Ctrl]+[C]	# 強制終了

実数データの処理

double型の実数データ1個あたりの情報量は 8 byte, 数値範囲は±約1.0×10±308, 有効数字は15桁となっている.

double は double precision(倍精度)を意味する. これだけだとわけわからんよね... 元々,単精度 4 byte の float があり, これが基本の実数型 floating point number(浮動小数点数)だった.

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);
}
...
$  ./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...不定値,非数
数学的に... 任意の数 a に対して,a ✕ 0 = 0 が成り立つ. この式を変形すると,a = 0÷ 0 となる. つまり,0 ÷ 0 の結果はどんな数にも一致することになり, 1つの数には定められない.

入出力の書式指定のまとめ

実験:書式指定をわざと間違えてみよう.format.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, y, z;	// 初期化しないと...
	printf("%d %d %d\n", x, y, z);	// どんな値?
	return (0);
}

ゴミ(無意味な値)が入っている. また,実行しなおす度に異なる結果となる.


本日の課題

  1. 整数を 10進数(decimal)として入力すると 16進数(hexadecimal)に変換して出力するプログラム d2x.c を作成せよ.
  2. ヒント: 何かを計算させる必要はない. 表示形式を変えるだけ.

    実行例:

    $  ./d2x
    10進数 > 255
    16進数 = FF
    
    10進数 > 16
    16進数 = 10
    
    ...
    
  3. 整数の 16進 → 10進変換の練習用プログラム x2dq.c を作成せよ.
  4. 要求仕様:次の動作を永久に繰り返す:

    実行例:

    $  ./x2dq
    16進数を10進数に変換しなさい.
    0x67 > 100
    ☓ :正解は 103 です.
    0xC6 > 198
    ◯
    0x69 > 105
    ◯
    .
    .
    .
    
    ヒント:第2回の授業練習問題を参考にせよ. 乱数 0〜255 は式 rand()%256 で生成できる. 終了方法は [Ctrl]+[C] でも [Ctrl]+[D] でもよい.

提出:


(c) 2018, yanagawa@kushiro-ct.ac.jp