C言語入門
シーげんごにゅうもん

PCinfo トップページプログラミング専門分野ハードウエアその他

関数を自作しよう

すでに私達はいくつかの関数を見てきました。例えば、main関数、printf関数、fopen関数、rand関数などです。 そして、これらの関数を組み合わせることによって、プログラムは作られてゆくのでしたね。

例えば、printf関数を使うと、その引数に指定した文字列や数値がディスプレイ上に表示されます。 しかし、私達はこのprintf関数がどのような仕組みでもってディスプレイ上に表示しているのかなど 知らなくても構わないのです。ただ、引数に出力したい文字列、数値を書けばいいという、printf関数の使い方さえ 分かっていればよいのです。実に便利です。

では、そんな便利な関数を自分でも作ってみようではありませんか。 C言語では、始めから用意されている関数を使うだけではなく、自ら作ることもできるのです。 では、構造体の話のところで作ったプログラムを流用して、学生のデータを入力する関数 を自作してみましょう。

#include <stdio.h>

struct student_data{
	int age;
	char name[100];
	char number[30];
	char address[300];
	char tel[40];
}card;

void data_input()
{
	printf("年齢を入力してください");
	scanf("%d",&card.age);
	printf("名前を入力してください");
	scanf("%s",&card.name);
	printf("学生番号を入力してください");
	scanf("%s",&card.number);
	printf("住所を入力してください");
	scanf("%s",&card.address);
	printf("電話番号を入力してください");
	scanf("%s",&card.tel);
}

int main(int, char**)
{
	data_input();/*自作関数の呼び出し*/

	printf("あなたの年齢は%d才で、\n名前は%sで、\n学生番号は%sで、\n住所は%sで、\
		\n電話番号は%sの学生です\n",\
		card.age, card.name, card.number, card.address, card.tel);

	return 0;
}

data_input関数が今回作った自作関数です。戻り値と引数無しのシンプルな奴です。

自作関数を作って分かることは、main関数の中身が随分とスッキリしたと思いませんか? 小規模なプログラムでは気付きにくいことなのですが、プログラムがある程度の大きさになってくると、 処理を関数化することによって、プログラムの見通しが良くなるのです。

では、調子に乗って、表示部分も関数にしてしまいましょう。

#include <stdio.h>

struct student_data{
	int age;
	char name[100];
	char number[30];
	char address[300];
	char tel[40];
}card;

void data_input()
{
	printf("年齢を入力してください");
	scanf("%d",&card.age);
	printf("名前を入力してください");
	scanf("%s",&card.name);
	printf("学生番号を入力してください");
	scanf("%s",&card.number);
	printf("住所を入力してください");
	scanf("%s",&card.address);
	printf("電話番号を入力してください");
	scanf("%s",&card.tel);
}

void data_output()
{
	printf("あなたの年齢は%d才で、\n名前は%sで、\n学生番号は%sで、\n住所は%sで、\
		\n電話番号は%sの学生です\n",\
		card.age, card.name, card.number, card.address, card.tel);
}

int main(int, char**)
{
	data_input();/*学生データを入力して*/

	data_output();/*そのデータをこの関数で出力!*/

	return 0;
}

メイン関数の中が、実にスッキリしました。清々しいくらいに(^○^)

関数化したお陰で、「入力した学生データを、画面上に出力するプログラム」なんだと、 その処理内容がクリアに分かるようになりました。

また、関数を自作することのメリットはそれだけに留まりません。作った関数は、 同一プログラム内で何度も使用できるので、同じような処理を何度も記述する必要から 開放されます。また、その関数を別のプログラムで利用することも可能になります。

複数のプログラムでの利用を考えるなら、できるだけ汎用的な記述を 心掛けるようにしましょう。

目次へ







型変換(キャスト)

では、今回は型の変換についてみていきましょう。
まず、次のプログラムを見てください。

#include <stdio.h>

int main(int, char**)
{
	printf("%f\n", 1/2);
	return 0;
}

これは1/2の計算結果を画面上に表示するというごく簡単なプログラムですが、 一体この計算結果はどのように表示されると思いますか?

実は0.000000と表示されてしまうのです。

私達は当然0.5と表示されることを期待している訳ですが、整数と整数の計算結果は 整数になるというルールがありまして、小数点以下の数値は問答無用で 切り捨てられてしまうのです。そのため、この計算結果は0となってしまったのです。

では、0.5の結果を得ようと思ったらどうすればよいのでしょうか? 答えは簡単!実数同士の演算にしてしまえばよいのです。

	printf("%f\n", 1.0f/2.0f);

これで、期待通りの0.500000という結果を得ることができました。

また、これ以外にも、型キャストを利用することによって強引に整数値を 実数値に変換してしまうという方法もあります。例えば最初のプログラムを次のように 書きなおすことによって期待する結果を得ることも可能です。

	printf("%f\n", (float)1/(float)2);

また、C言語においては、異なる型同士の演算がサポートされています。つまり、整数と実数という 異なるデータ型同士の演算も可能ということです。例えばint型とfloat型の計算を行う場合、 int型のデータは自動的にfloat型に変換されることになるのです。このことを型の昇格といいまして、 昇格の関係は大雑把に次のようになっています。


char ⇒ int ⇒ long ⇒ float ⇒ double


この型の昇格がサポートされているお陰で、次のように書いても、期待する結果を得ることができます。

	printf("%f\n", 1.0f/2);

では最後に、型キャストに関する注意事項を話しておきましょう。

例えばchar型からint型への変換は問題ありませんが、逆にint型からchar型へ変換する場合などは 注意が必要です。int型という大きいサイズをchar型の小さいサイズに強引に変えてしまう訳ですから、 データが一部損失してしまう可能性があるのです。

では次の例を見てください。

#include <stdio.h>

int main(int, char**)
{
	int a=123456;
	printf("%d\n", (char)a);
	return 0;
}

この場合の表示結果は64となってしまい、データが損失していることが確認できます。
ただ、このキャストによりデータが損失してしまうという性質を利用して、float型から int型にキャストして小数点以下の切り捨てを行うこともできます。

目次へ







共用体の話

では今回は、構造体に非常によく似た共用体についてお話しましょう。
あれこれ説明する前に、共用体の作り方をみてみましょう。

union タグ名{
	型 メンバ1;
	型 メンバ2;
}変数リスト;

では復習までに構造体の作り方も思い出してみましょう。

struct タグ名{
	型 メンバ1;
	型 メンバ2;
}変数リスト;

unionかstructの違いだけかいっ!って感じですね。
共用体を理解するには、構造体との違いを知ることが一番です。

構造体と共用体では、メモリ上への領域確保の方法が違います。例えば構造体で次のように 定義したとしましょう。

struct struct_data{
	char	a;
	short	b;
	long	c
}data;

この場合、メモリ上にcharの1バイト、shortの2バイト、longの4バイトの合計7バイト の記憶領域が割り当てられることになります。

それに対し共用体で次のように定義した場合、

union union_data{
	char	a;
	short	b;
	long	c
}data;

構造体の場合と違い、メンバの中で最も大きいデータ型の領域がメモリ上に確保されることになります。 ですので、このケースの場合long型の4バイトが確保されます。そして、他のメンバもこの領域を 共有・共用することになるのです。

そのため当然、共用体を作る目的は構造体とは違ったものになります。上記の共用体のdataという変数は、 時として、char型の変数としても使えるし、long型としても使えるという特性を持つことになります。 つまり、共用体を使うと型に依存しない変数を作ることが出来るのです。

目次へ







未定

まだ未定。

目次へ








未定

未定

目次へ