データを扱う


コンピュータ上で、プログラム(ソフトウェア)が何をするのか一言で表現すると、「ある手順(アルゴリズム)でデータを加工する」となります。これは全てのプログラムにおいて言えることです。
では、データと簡単に言いますが、データって何なんでしょう?
コンピュータ上でのデータとC言語について考えます。


データとは何か

 「人間は考える葦である」…… Blaise Pascal (1623〜1662)
 数学、物理学、哲学などの分野で大きな足跡を残したパスカルの有名な言葉です。人間は葦のように弱々しい生物にすぎないが、いろいろ難しいことを考えられる、と言っています。では、考えるという行為は、一体何なんでしょう?
 人間が何かを考える場合、考える対象があるのが普通です。考えるという行為は、「〜について考える」と表現されますよね。例えば「出席日数について考える」場合、頭の中にカレンダーや出席簿を思い浮かべて、そこに自分の出席状況を書き込んでいって、足りる、足りない、今日はまだ休める、とやることになるでしょう。これが、考えるという行為の正体なのです。
 この、考える行為の正体をもとに、我々が普段、物知り顔にデータと呼んでいるものが何かと考えます。先程の出席日数の例で、データらしきものが出てこなかったか考えてみると、どうやら頭の中に思い浮かべた出席簿の出欠の付き具合がデータだと言えそうです。
 データとは、抽象概念で、その表現媒体を複数持つことが出来ます。つまり、自分の出欠データは、出席簿、カレンダー、Excel形式のファイル、いずれの形式でも同じ内容のものが表現できます。これは、情報(例えば、事件のニュース)が、さまざまなメディア(新聞、TV、ラジオ、インターネット、口コミ、etc)で伝えられるのとまったく同様です。
 考える行為には、データを元に、別のデータを生成するという側面があります。出席日数について考える時は、自分の現時点での出欠データを元に、今後休めるかどうか、あと何日休めるかといったデータを生成します。
 コンピュータ上のプログラム(ソフトウェア)は、あるデータを元に別のデータを生成するという行為を、人間に代わって行っています。今回は、こうしたデータという抽象概念を、C言語上でどのように表現できるのかについて見ていくことにします。

C言語上でのデータ形式

 我々の頭の中の抽象概念であるデータでは、ありとあらゆるものが扱われます。例えば、
・冷蔵庫に残っている卵の個数
・昨夜の睡眠時間
・芸能人の名前
・出欠状況
・会社を辞める前にしばく奴リスト
といったものがデータとして扱われます。
 こうしたデータをC言語上で扱う為には、データの形式を考えてやる必要があります。卵の個数は自然数で表現できますが、芸能人の名前は文字列でないと表現できません。C言語上では、データの形式に応じて、データの表現方法が異なります。表現したいデータの形式に応じた表現方法を使ってやらないといけないわけです。
 C言語上では、データの表現方法として、変数、配列、構造体などを用います。それでは実際に、どのようなデータが、どういった表現方法で表されるのか見てみることにしましょう。

変数

 C言語上で使用できるデータ表現で、もっとも基本的なのが変数です。変数とは、入れられるデータの型が限定された箱のことです。この変数には、名前を付けてやることができ、プログラムを記述する中で、使いたい変数を作成してから使用します。一部のプログラミング言語では、明示的に作成しなくとも、好きなように変数を使える場合がありますが、C言語では必ず型と名前を指定して、使用する変数を作成してやらなければなりません。
 一般的に、変数を作成することを、「変数の宣言」と呼んでいますが、本稿では「作成」という表現を用いることにします。

List.1:list1.c


#include <stdio.h>

int main()
{
	a = 1;

	printf("a is %d\n", a);

	return 0;
}

List.2:list2.c


#include <stdio.h>  

int main()
{
	int a;

	a = 1;

	printf("a is %d\n", a);

	return 0;
}

整数型変数
 整数値を入れることが出来る箱のことを、整数型変数といいます。例えば、aという名前の整数型変数を作りたい場合は、ソースファイル内で、
int a;
という具合に記述します。この一文によって、整数型変数aが使用できるようになります。 例えば、list.1をコンパイルしてみてください。list.1では
a = 1;
の行で、変数aに数値1を入れようとしていますが、aを作る記述が見当たらないので、コンパイルできません。list.2のように、変数を作成してから使うようにしないと、文法上誤りになります。list.2がちゃんとコンパイルできることを確認して下さい。
 整数型変数には、intの他にもchar、short、longといった型があります。また、変数に負の値を入れない場合には、unsigned int、unsigned char、unsigned short、unsigned longといった型を使うこともできます。
 整数型の変数が、何故こんなにもたくさんあるのかという話は、のちほど解説します。

List.3:list3.c


#include <stdio.h>  

int main()
{
	int a;
	float b;

	a = 1.3;
	b = 1.3;

	printf("a is %d\nb is %f\n", a, b);

	return 0;
}

浮動小数点型
 世の中に存在する数値は整数だけではありませんので、先程の整数型変数では扱えない数値も存在します。例えば、小数点以下を含む数値もそうした数値の一種です。小数点以下を含む数値でも、小数点以下の数値の桁数が固定されている場合などは、その分繰り上げて整数扱いにしても、意味を変えないで扱うことが可能ですが、小数点以下の数値の桁数が固定できない場合(科学技術計算など、高い計算精度の要求される場合)には、そうしたテクニックが使えません。また、整数型では、扱える数値の範囲が決まっている(詳細は後述)ので、極端に大きさの違う数値同士を演算することには向いていません。
 浮動小数点型は、数値を仮数と指数に分解して保持します。例えば、「126.71」を「1.2671 x 10^2」という内部表現にして保持するとイメージすればよいでしょう。こうすることで実数範囲の数値を扱えるようにしているわけです。実際に使う側では、この内部表現を意識しないで使用できます。bという名前の浮動小数点型変数を作りたい場合は、ソースファイル内で、
float b;
と記述します。list.3では、
b = 1.3;
の行で、変数bに数値1.3を入れています。整数型変数aにも1.3を入れていますが、これは正しく数値を入れることが出来ません。整数型変数に小数点以下のある数値を入れようとすると、大抵の場合(使用するコンパイラによって違う可能性がある)、小数点以下が切り捨てられた整数が入ります。つまり、この場合、aには1が入ります。
 浮動小数点型にはfloatの他に、倍精度浮動小数点型double、拡張精度浮動小数点型long doubleを使用することができます。これらは名前から想像できるように、極めて高い精度が必要になった時などにfloatの代わりに使うと良いでしょう。

演習:list.2、list.3を参考にlist.4に書き足して、short型変数widthに640を入れ、double型変数mathに1.4142を入れるプログラムを完成させよ。

List.4:list4.c


#include <stdio.h>  

int main()
{
/* ここから */

/* ここまでに書く */

	printf("width is %d\math is %f\n", width, math);

	return 0;
}

変数に初期値を与える
 変数には、作成時に初期値を与えることができます。例えば、float型変数bを作成した直後に1.3という値を入れるために
float b;
b = 1.3;
と2行書くところを
float b = 1.3;
と1行で記述することができます。

演習:list.2、list.3を、変数に初期値を与える形で書き直せ。

配列

 変数は、1個の箱を作って、1個の数値を入れるというものです。しかし、さまざまなデータを表現しようと考えた場合、明らかに役不足です。例えば、毎朝の朝食のカロリーを表現したいと思っても、今日の分、昨日の分と日ごとのデータを変数に入れることはできますが、それらは所詮別々の独立した変数ですから、今ひとつ扱い難くなります。C言語では、同じ型の複数の変数をまとめて扱う為に、配列という仕組みが使えます。配列では、変数の集団に名前を付け、集団内の個々の変数を区別するために番号付けを行います。例えば、int型の変数10個からなる配列をcという名前で作りたければ、
int c[10];
と記述します。すると、c[0]〜c[9]までの10個の変数を使うことが出来るようになり、
c[0] = 10;
c[9] = -11;
ということが可能になります。[]の中の数は0から始まるの事に注意して下さい。

数列を表現する
 配列の用途としてもっとも基本的なのが、長さの決まっている数列を表現することです。例えば、4/1〜4/10の間の毎朝の朝食のカロリーなどを表現することができます。fig.1を配列で表現すると、list.5のようになります。double型変数10個からなる配列calを作成し、0番目から順に毎朝のカロリーを入れています。

Fig.1:4/1〜4/10の間の毎朝の朝食のカロリー

日付 4月1日 4月2日 4月3日 4月4日 4月5日 4月6日 4月7日 4月8日 4月9日 4月10日
カロリー 137.2 0 67.5 33 98.72 0 76.3 44.7 102.5 86.3

List.5:list5.c


#include <stdio.h>  

int main()
{
	double cal[10];

	cal[0] = 137.2;
	cal[1] = 0;
	cal[2] = 67.5;
	cal[3] = 33;
	cal[4] = 98.72;
	cal[5] = 0;
	cal[6] = 76.3;
	cal[7] = 44.7;
	cal[8] = 102.5;
	cal[9] = 86.3;

	printf("4/1  %f cal\n", cal[0]);
	printf("4/2  %f cal\n", cal[1]);
	printf("4/3  %f cal\n", cal[2]);
	printf("4/4  %f cal\n", cal[3]);
	printf("4/5  %f cal\n", cal[4]);
	printf("4/6  %f cal\n", cal[5]);
	printf("4/7  %f cal\n", cal[6]);
	printf("4/8  %f cal\n", cal[7]);
	printf("4/9  %f cal\n", cal[8]);
	printf("4/10 %f cal\n", cal[9]);

	return 0;
}

演習:list.5を参考にlist.6に書き足して、int型配列mにfig.2のデータを入れるプログラムを完成させよ。

Fig.2:定例会議の出席人数

日付 3月1日 3月8日 3月15日 3月22日 3月29日 4月5日 4月12日
出席 人数 12 18 10 16 9 19 14

List.6:list6.c


#include <stdio.h>  

int main()
{
/* ここから */

/* ここまでに書く */

	printf("3/1  %d\n", m[0]);
	printf("3/8  %d\n", m[1]);
	printf("3/15 %d\n", m[2]);
	printf("3/22 %d\n", m[3]);
	printf("3/29 %d\n", m[4]);
	printf("4/5  %d\n", m[5]);
	printf("4/12 %d\n", m[6]);

	return 0;
}

List.7:list7.c


#include <stdio.h>  

int main()
{
	char str[] = "ABCDEFG";

	printf("str is %s\n", str);

	return 0;
}

文字列を表現する
 さまざまな型の変数や、それを配列として利用できることを紹介してきましたが、「なんや、C言語って数字しか扱えへんのか」と思う方もおられるかも知れません。特に、文字列を入れる専用の変数型を持つプログラミング言語を知っている方は、そう思われるでしょう。C言語には、文字列を入れる変数型はありません。では、どうやって文字列を扱うのでしょう。
 先程、整数型変数として、char型を紹介しましたが、この「char」という名前は、「character」に由来しています。この場合の「character」の意味は「文字」です。つまり、char型変数は、もともと、文字を入れる変数型なのです。現在の日本においては、char型変数に日本語の文字を入れることは一般的に不可能になっていますが、このchar型変数の配列を用いて、文字列を表現することは一般的に行われています。例えば、
char str[] = "ABCDEFG";
という1行で、char型配列strを、文字列「ABCDEFG」が収まる長さを自動的に求めて作成し、実際にstrに「ABCDEFG」という文字列を入れることができます。(list.7)
 現在一般的なCコンパイラの仕様では、俗に半角と呼ばれている文字はchar型変数1個分で表すことができ、俗に全角と呼ばれている文字はchar型変数2個分であらわすことができます。また、char型変数の配列で文字列を表現する場合、文字列の終端を表すために、char型変数1個分が必要になります。さきほどの「ABCDEFG」を表すために必要なchar型配列の長さは8になりますので、さきほどのchar型配列strは、0から7までの8個のchar型変数で構成されることになります。

演習:list.7を参考にlist.8に書き足して、char型配列strに「OPQRSTUVW」を入れるプログラムを完成させよ。また、このとき生成されるchar型配列strの長さはいくつになるか?

List.8:list8.c


#include <stdio.h>  

int main()
{
/* ここから */

/* ここまでに書く */

	printf("str is %s\n", str);

	return 0;
}

Fig.3:九九

  1 2 3 4 5 6 7 8 9
1 1 2 3 4 5 6 7 8 9
2 2 4 6 8 10 12 14 16 18
3 3 6 9 12 15 18 21 24 27
4 4 8 12 16 20 24 28 32 36
5 5 10 15 20 25 30 35 40 45
6 6 12 18 24 30 36 42 48 54
7 7 14 21 28 35 42 49 56 63
8 8 16 24 32 40 48 56 64 72
9 9 18 27 36 45 54 63 72 81

List.9:list9.c


#include <stdio.h>  

int main()
{
	int kuku[9][9];

	kuku[0][0] = 1;
	kuku[0][1] = kuku[1][0] = 2;
	kuku[0][2] = kuku[2][0] = 3;
	kuku[0][3] = kuku[3][0] = 4;
	kuku[0][4] = kuku[4][0] = 5;
	kuku[0][5] = kuku[5][0] = 6;
	kuku[0][6] = kuku[6][0] = 7;
	kuku[0][7] = kuku[7][0] = 8;
	kuku[0][8] = kuku[8][0] = 9;
	kuku[1][1] = 4;
	kuku[1][2] = kuku[2][1] = 6;
	kuku[1][3] = kuku[3][1] = 8;
	kuku[1][4] = kuku[4][1] = 10;
	kuku[1][5] = kuku[5][1] = 12;
	kuku[1][6] = kuku[6][1] = 14;
	kuku[1][7] = kuku[7][1] = 16;
	kuku[1][8] = kuku[8][1] = 18;
	kuku[2][2] = 9;
	kuku[2][3] = kuku[3][2] = 12;
	kuku[2][4] = kuku[4][2] = 15;
	kuku[2][5] = kuku[5][2] = 18;
	kuku[2][6] = kuku[6][2] = 21;
	kuku[2][7] = kuku[7][2] = 24;
	kuku[2][8] = kuku[8][2] = 27;
	kuku[3][3] = 16;
	kuku[3][4] = kuku[4][3] = 20;
	kuku[3][5] = kuku[5][3] = 24;
	kuku[3][6] = kuku[6][3] = 28;
	kuku[3][7] = kuku[7][3] = 32;
	kuku[3][8] = kuku[8][3] = 36;
	kuku[4][4] = 25;
	kuku[4][5] = kuku[5][4] = 30;
	kuku[4][6] = kuku[6][4] = 35;
	kuku[4][7] = kuku[7][4] = 40;
	kuku[4][8] = kuku[8][4] = 45;
	kuku[5][5] = 36;
	kuku[5][6] = kuku[6][5] = 42;
	kuku[5][7] = kuku[7][5] = 48;
	kuku[5][8] = kuku[8][5] = 54;
	kuku[6][6] = 49;
	kuku[6][7] = kuku[7][6] = 56;
	kuku[6][8] = kuku[8][6] = 63;
	kuku[7][7] = 64;
	kuku[7][8] = kuku[8][7] = 72;
	kuku[8][8] = 81;

	printf("3 x 8 = %d\n", kuku[2][7]);

	return 0;
}

行列を表現する
 数値が順番に並んでいる数列を表現するのに配列が使えることは紹介したとおりですが、こうした配列を1次元配列と呼ぶ場合があります。数値が一直線に並ぶので、1次元なわけです。わざわざ1次元と呼ぶということは、1次元でない配列も利用できるということで、C言語では、2次元配列や3次元配列といった多次元配列を使用することもできます。
 例えば、九九の表(fig.3)などは、縦横2つの方向に数値が並びますが、数学ではこういった構造をもった数値群のことを行列と呼んでいます。数列も、1次元の行列と考えることができますね。
 実際にfig.3の行列を入れるためのint型2次元配列kukuをつかった例がlist.9になります。

演習:fig.4の表を完成させ、list.9を参考にlist.10に書き足して、double型2次元配列perにfig.4のデータを入れるプログラムを完成させよ。

Fig.4:割り算

  1 2 3 4 5
1 1 2 3 4 5
2 0.5 1 1.5 2 2.5
3          
4          
5          

List.10:list10.c


#include <stdio.h>  

int main()
{
/* ここから */

/* ここまでに書く */

	printf("3 / 2 = %f\n", per[2][1]);

	return 0;
}

Fig.5:身体測定の結果

  川端 長久 松浦 松本
年齢 43 28 33 43
身長 170.4 165.5 168.2 171.3
体重 73.3 64.5 68.5 72.7
右目 視力 0.3 1.2 1.2 1.0
左眼 視力 0.2 1.5 1.2 1.0

List.11:list11.c


#include <stdio.h>  

int main()
{
	int kawabata_age = 43;
	int nagaku_age = 28;
	int matsuura_age = 33;
	int matsumoto_age = 43;
	double kawabata_length = 170.4;
	double nagaku_length = 165.5;
	double matsuura_length = 168.2;
	double matsumoto_length = 171.3;
	double kawabata_weight = 73.3;
	double nagaku_weight = 64.5;
	double matsuura_weight = 68.5;
	double matsumoto_weight = 72.7;
/* 0番目を右目視力、1番目を左眼視力とする */
	double kawabata_eyes[2] = {0.3, 0.2};
	double nagaku_eyes[2] = {1.2, 1.5};
	double matsuura_eyes[2] = {1.2, 1.2};
	double matsumoto_eyes[2] = {1.0, 1.0};

	printf("nagaku status\n");
	printf("age = %d\n", nagaku_age);
	printf("length = %f\n", nagaku_length);
	printf("weight = %f\n", nagaku_weight);
	printf("right eye = %f\n", nagaku_eyes[0]);
	printf("left eye = %f\n", nagaku_eyes[1]);

	return 0;
}

List.12:list12.c


#include <stdio.h>  

struct status {
	int age;
	double length;
	double weight;
	double eyes[2];
};

int main()
{
	struct status member_status[4];

	member_status[0].age = 43;
	member_status[1].age = 28;
	member_status[2].age = 33;
	member_status[3].age = 43;
	member_status[0].length = 170.4;
	member_status[1].length = 165.5;
	member_status[2].length = 168.2;
	member_status[3].length = 171.3;
	member_status[0].weight = 73.3;
	member_status[1].weight = 64.5;
	member_status[2].weight = 68.5;
	member_status[3].weight = 72.7;
	member_status[0].eyes[0] = 0.3;
	member_status[0].eyes[1] = 0.2;
	member_status[1].eyes[0] = 1.2;
	member_status[1].eyes[1] = 1.5;
	member_status[2].eyes[0] = 1.2;
	member_status[2].eyes[1] = 1.2;
	member_status[3].eyes[0] = 1.0;
	member_status[3].eyes[1] = 1.0;

	printf("nagaku status\n");
	printf("age = %d\n", member_status[1].age);
	printf("length = %f\n", member_status[1].length);
	printf("weight = %f\n", member_status[1].weight);
	printf("right eye = %f\n", member_status[1].eyes[0]);
	printf("left eye = %f\n", member_status[1].eyes[1]);

	return 0;
}

構造体

 C言語は、より人間の考えるデータに近いものを表現するために、構造体というデータ表現を持っています。構造体は、内部に様々なデータ型を持つことができ、そうすることで自分で新しいデータの型を作ることができます。
 例えば、人間の身体的特徴を表現するデータ型を、構造体を用いて作ってみることにしましょう。まず頭の中に、身体測定のときに、身長や体重を記入する紙を思い浮かべてください。次のような項目が並んでいるとします。
・年齢
・身長
・体重
・右目視力
・左眼視力
これに基づいた身体測定の結果がfig.5だったとします。
 年齢はint型、その他はdouble型で表現するとして、とりあえず全部変数に入れておけるようにしてみるとlist.11のようになります。確かに全てのデータを入れることはできましたが、誰の何のデータなのかを区別する手段は変数名しかありません。それに、全てのデータ分、変数の作成を行わなければならないのも面倒ですね。
 list.11と同じ内容を、構造体を使って表現したのがlist.12になります。
 構造体を使う場合には、まず構造体の型を定義します。list.12では

struct status {
	int age;
	double length;
	double weight;
	double eyes[2];
};
の部分でstatus構造体の定義を行っています。status構造体は、その内部に年齢、身長、体重、視力のデータを持つ構造体として定義されています。こうした構造体内部のデータのことをメンバーと呼びます。status構造体は、age、length、weight、eyesをメンバーとして持っているわけです。
 status構造体は1人分の身体データを持てるようにできているので、4人分のデータを持てるようにするには、この型の構造体を4つ作ればよいことになります。list.12では
struct status member_status[4];
の部分で、status構造体4つ分を配列としてstatus構造体配列member_statusとして作成しています。構造体は、いわば新しいデータ型を自分で作るための仕組みで、定義した構造体は、int型やfloat型の変数と同じように、作成したり、配列として作成したりできます。
 実際に構造体のメンバーにデータを入れたりする為には、『「構造体名」.「メンバー名」』という書式を使います。member_status[0]のageに43を入れたければ
member_status[0].age = 43;
と記述します。
 C言語によるプログラミングでは、構造体を如何に使いこなすかが重要なテーマになります。扱いたいデータの構造に合わせた構造体を使うことで、理解しやすいソースを書くことができるからです。理解しやすい、読みやすいソースは、他の人のためというよりも、後で自分が見直すときや、何故ちゃんと動かないのか考えるときのために重要なのです。

演習:fig.6のデータを扱うために、address構造体の定義を考え、list.12を参考にlist.13に書き足して、address構造体配列member_addressにfig.6のデータを入れるプログラムを完成させよ。

Fig.6:住所録

  有川 高橋 長久 福原 山本
年齢 29 29 28 28 29
郵便番号 111-1111 111-1222 222-1111 333-1111 111-1333
都道府県 大阪府 大阪府 東京都 京都府 大阪府
電話 番号 06-4444-4444 06-5555-5555 03-6666-6666 075-777-7777 06-8888-8888

List.13:list13.c


#include <stdio.h>  

/* 構造体の定義を、ここから */

/* ここまでに書く */

int main()
{

/* 構造体の作成以下を、ここから */

/* ここまでに書く */

	printf("nagaku address\n");
	printf("age = %d\n", member_address[2].age);
	printf("postal number = %s\n", member_address[2].postal_number);
	printf("prefecture = %s\n", member_addresss[2].prefecture);
	printf("tel number = %s\n", member_addresss[2].tel_number);

	return 0;
}

Fig.7:変数の情報量一覧

データ 情報 (バイト)
char 1
unsigned char 1
short 2
unsigned short 2
long 4
unsigned long 4
int 4
unsigned int 4
float 4
double 8
long double 10

List.14:fig.7を求めるlist14.c


#include <stdio.h>  

int main()
{
	printf("char size = %d\n", sizeof(char));
	printf("unsigned char size = %d\n", sizeof(unsigned char));
	printf("short size = %d\n", sizeof(short));
	printf("unsigned short size = %d\n", sizeof(unsigned short));
	printf("long size = %d\n", sizeof(long));
	printf("unsigned long size = %d\n", sizeof(unsigned long));
	printf("int size = %d\n", sizeof(int));
	printf("unsigned int size = %d\n", sizeof(unsigned int));
	printf("float size = %d\n", sizeof(float));
	printf("double size = %d\n", sizeof(double));
	printf("long double size = %d\n", sizeof(long double));

	return 0;
}

ビットとバイト

 「コンピュータの中は全部デジタルだから1と0しかない」とよく表現されますが、いったいどういうことなんでしょう?
 現在のコンピュータではあらゆる情報を1/0の列で表現するようになっています。数値の場合、内部では2進数で保持されます。例えば、

10進数  2進数
    12 → 1100
      7 → 111

というふうに表現されます。この1か0しかない1桁分の情報容量を「ビット」と呼んでいます。1ビットで表現できる数値は0と1だけです。2ビットでは0、1、2、3を表現できます。
 現在のコンピュータでは、8ビットをまとめて扱うことがほとんどで、8ビット分のことを「バイト」と呼んでいます。メモリー何メガバイトのあのバイトです。1バイトあれば00000000から11111111までの数値を表現可能になり、これは10進数に直すと0から255に相当します。
 コンピュータの内部では、変数などのデータもすべて、情報容量を規定された2進数で表現されています。例えば、char型は1バイト分の情報容量、short型は2バイトの情報容量というふうになっています。(fig.7)
 またunsignedでない整数型変数では、負の数を表現するために、表現できるバリエーションの半分を、負の値として扱うように規定されています。例えばchar型の場合、0〜127はそのままの数値として扱われますが、128〜255は負の値として扱われ、255は-1、128は-128を表していると解釈されます。このことは、char型の場合、127に1を加えると-128になってしまうことを表しています。これは具合が悪いですね。
 整数型変数の説明のとき、なぜ同じ整数を表すための変数型がたくさんあるのかという疑問を持たれたかも知れませんが、その答えがここにあるわけです。128という数値を扱いたければ、char型は使えない、つまり、整数型変数は入れられる値の種類が決まっているだけでなく、入れられる値の上限下限も決まっているので、扱う値の大きさによっても使い分けなければならないのです。
 浮動小数点型変数においても、仮数、指数の上限下限が情報容量によって決まってくるので、多くの情報容量を必要とする型ほど、高い精度で広い範囲の値を扱えるようになっています。
 こうやって考えると、とにかく情報容量の大きい型を使えば安心と言えるのですが、メモリーは有限量なので、扱えるデータの数は減ってしまいます。莫大な量のデータを処理する場合は、必要最小限の情報容量を持つ型を用いるようにしなければなりません。

演習:我々人間は、普段両手の指を使って10までの数を数えていますが、工夫すると0〜1023までの数を数えることができます。どうすればそんなに大きな数が数えられるのでしょう?

まとめ

 今回は「C言語上でどのようにデータを表現するか」について考えてみました。どんな型が使えるかが重要なのではなく、どんなデータをどんな型で表現するのかが大事なのです。
 プログラミングでは、自分のやりたいことをどう表現するかが重要なので、文法を知っていても、それをどう使えばよいか考えられなければダメです。身の回りにある様々なデータをC言語で表現する訓練をして下さい。
 また、数値を仮数、指数で表現することや、数列、行列、2進数といった、数学で用いられる概念がいくつか出てきました。プログラミングにおいては、数学的概念を応用して問題解決を図ることがよくあります。理系カリキュラムの高校レベルの数学の知識があれば、より深く理解することができるでしょう。
 次回は「演算を行う」です。データを演算によって加工し、のぞむ結果を得ることについて解説します。

 それでは。

ソースファイル一式


コラム

コンパイラのメッセージ
 list.11をコンパイルするとき、使用するコンパイラによっては、メッセージが出るかも知れません。コンパイラは、自身に分かる範囲で、ソースプログラム中の間違いや間違いかも知れないものを知らせてくれるのです。明らかに間違いである場合はエラー(ERROR)として、間違いかも知れない場合は警告(WARNING)として、問題部分のソースプログラム中での行番号と一緒に教えてくれます。list.11の場合は、「おまえいろいろ変数作ってるけど、使ってないぞ。いいのか?」と教えてくれます。
 プログラミング初心者がよく犯す過ちとして、「コンパイラのメッセージをまったく見ない」というものが挙げられます。コンパイラのメッセージが英語で、訳しても意味を理解できないことが多いのでしょうが、わざわざ「ここが間違っている」と教えてくれているのを無視して「どこが間違っているんだろう?」と悩んでいる人をよく見かけます。
 最近のコンパイラは、付属資料も充実しているので、英語のメッセージであっても、その意味を知るための方法は用意されていると思います。面倒がらずに、コンパイラのメッセージを読んで理解するように心がけて下さい。最低でも、メッセージに記された行番号はチェックするようにしましょう。

16進数
 コンピュータの内部では全て2進数で記憶されるわけですが、C言語では意外なことに、ソースに直接2進数を表記する手段が用意されていません。
int a = 01101100;
のようなイメージでの記述ができないのです。
 C言語では2進数表記が使えない代わりに、16進数による表記を多用します。さきほどのイメージを16進数を用いて記述すると、

2進数        16進数
01101100 → 6C

なので
int a = 0x6C;
と書けます。16進数表記を行う場合には、数値の頭に「0x」を付けることで、10進数表記と区別します。