おまけ

[PDF版]

構造体の代入、引数渡し、返り値、sizeof演算子

構造体とは、いくつかのデータをひとまとまりにしたものです。プログラマに とってはコンピュータの中で何かをさせたい場合にそれを表現するためには必 要な機能です。

前回の最後にデータ型について、説明しましたが、同じデータ型同士であれば、 代入ができます。例えば、座標を表すpointという名前の構造体定義されてい るものとしましょう。

struct point { int x,y; }; /* 構造体の定義 */
struct point A,B;
と宣言されていれば、以下のように代入できます。(演算はできません)
 A = B;
代入とは、構造体のコピーです。

当然、引数にも使うことができます。関数fooが以下のように定義されていれ ば、

void foo(struct point a, struct point b){ … }
これで、
foo(A,B);
と書けば、呼び出しに構造体をつかうことができます。以前、関数の説明をし ましたが、C言語の場合は「値渡し」です。つまり、引数の値はコピーされて、 引数として関数に渡されます。

また、関数の返り値としても返すことができます。例えば、以下のようにする ことができます。

struct point goo(…) {  struct point X; …. retrun X; }
受け取るほうは、
A = goo(…);
として、返り値をコピーすることができます。構造体は、データ型ですので、 intやdoubleと同じようにつかうことができます。struct pointと書くのが面 倒だったら、前回、説明したとおり、typedefをつかって、データ型を定義し ておけばすこしは書く量が減って、わかりやすくすることもできます。
typedef struct point point_type;
point_type A,B;
とかけます。

以上、代入、関数の引数、返り値、どれも、構造体の場合もintやdoubleと同 じように「コピー」されます。コピーなので、大きな構造体の場合は時間がか かってしまうことになります。では、どのくらいのサイズなのか。データ型の サイズは、sizeof演算子を使って調べることができます。例えば、intは、4バ イトなので、sizeof(int)は4になります。例えば、上の2つの整数をメンバー としてもつ構造体pointのサイズをしらべてみましょう。

printf("size is %d\n",sizeof(struct point));
を実行してみると、4バイトのintが2つなので、8とプリントされるはずです。

構造体とポインタ、malloc関数

構造体を上のように、直接、引数に使ってしまうと、コピーされるため、不効 率になってしまうことがあります。前の例では整数が2つだけなので、たいし たことはありませんが、100バイトもある構造体の場合はいちいちコピーして いたら、遅いプログラムになってしまいます。(実際、このような小僧体の代 入や引数は最初のC言語にはない機能でした。多くのプログラムでは構造体に 引数を直接かくことは注意する必要があります)

このような場合は、ポインタを使います。ポインタはプログラムを効率的なプ ログラムを書くための機能です。ポインタの宣言は、データ型のあとに*をつ けたものですから、前の例のpoint構造体へのポインタの宣言は、struct point * で宣言します。前の例の関数宣言を書き直してみましょう。

void foo(struct point *ap, struct point *bp){ … }
呼び出しのほうはポインタを渡すわけですから、&演算子を使って、ポインタ をつくって渡します。
foo(&A,&B);
ポインタからメンバーの値を参照するには、 ->演算子をつかいます。 たとえば、 apで指されている構造体から、メンバーxを参照するには、
t = ap->x + 1;
と書きます。これは左側にかけば、メンバーへの代入になります。
ap->x = 123;
これは、まず構造体を参照して、そのメンバーを参照すればいいので、ap->xは、
(*ap).x
ともかくことができます。しかし、->のほうがわかりやすいので、こちらを使うようにしましょう。

最後に、メモリを確保する関数にmallocという関数 があります。この関数は、malloc(確保するバイト数)で呼び出します。malloc 関数から返る値は、確保されたメモリのアドレス、つまりポインターです。使っ ているマシンの環境にもよりますが、malloc関数は文字へのポインター、つま り、char *で、<stdlib.h>で宣言されていることがおおいので、必要なメモリ を取ったあとは適当なデータ型のポインタに変えてやる必要があります。これ をやるのが、キャスト演算子です。

 ap = (struct point *)malloc(sizeof(struct point));
必要なバイト数はsizeof演算子を使って計算しています。 このように、プログラムの中で実行中にメモリを確保するようなプログラムでは構造体へのポインタは不可欠な機能です。