構造体
2018/10/23 - moriya - ~3 Minutes
未だに構造体に関する検索が多いようなので、少し書いてみようと思う。
他のサイトにも解説があるので、初学者の頃、自分がわかりづらかった点について書いてみようと思う。
構造体とは
複数の変数をひとまとめにして扱うようにしたもの。
例えば、座標のように (x,y) をまとめて扱えると便利だろう。
struct 構造体タグ名 {
型 変数; // メンバ変数と言う
:
};
のように宣言する。
例1:構造体の場合
// 実際に変数が割り当てられるわけではない。
struct point_st {
int x;
int y;
};
int
main(int argc, char *argv[])
{
struct point_st point;
point.x = 10; // 構造体のメンバ変数にアクセスする時は、"." を使う。
point.y = 20;
return 0;
}
例2:構造体へのポインタの場合
#include <stdlib.h>
struct point_st {
int x;
int y;
};
int
main(int argc, char *argv[])
{
struct point_st *pointp = (struct point_st *)malloc(sizeof(struct point_st));
// 構造体へのポインタの場合、->(アロー演算子と呼ばれているようだ)でアクセスする。
pointp->x = 10;
pointp->y = 20;
return 0;
}
わかりづらかった点
色々な書式があってわかりづらい。
以下は同じものだ。
パターン1:
struct point_st {
int x;
int y;
return 0;
};
struct point_st point;
パターン2:
typedef struct point_st {
int x;
int y;
} point_t;
point_t point;
パターン3 (タグ名省略):
typedef struct {
int x;
int y;
} point_t;
struct 〜 と書くのは、タイプ量も多いし、長くて読みづらいので、私は、パターン3をよく使う。
構造体自身へのポインタを含む場合の書き方がわからない。
リスト構造を作る場合に、構造体自身へのポインタを示す場合の書き方。
パターン1:
struct point_st {
int x;
int y;
struct point_st *next;
};
int main(int argc, char *argv[])
{
struct point_st *point1p;
struct point_st *point2p;
point1p = (struct point_st*)malloc(sizeof(struct point_st));
memset(point1p, 0, sizeof(struct point_st));
point1p->x = 1;
point1p->y = 2;
point1p->next = NULL;
point2p = (struct point_st*)malloc(sizeof(struct point_st));
memset(point2p, 0, sizeof(struct point_st));
point2p->x = 3;
point2p->y = 4;
point2p->next = point1p;
return 0;
}
パターン2:
typedef struct point_st {
int x;
int y;
struct point_st *next;
} point_t;
int main(int argc, char *argv[])
{
point_t *point1p;
point_t *point2p;
point1p = (struct point_st*)malloc(sizeof(struct point_st));
memset(point1p, 0, sizeof(struct point_st));
point1p->x = 1;
point1p->y = 2;
point1p->next = NULL;
point2p = (struct point_st*)malloc(sizeof(struct point_st));
memset(point2p, 0, sizeof(struct point_st));
point2p->x = 3;
point2p->y = 4;
point2p->next = point1p;
return 0;
}
同様に、読みやすさから、パターン2を使う。
構造体をどのようにして関数に渡すのかわからない
この構造体を他の関数にどのように渡すべきなのか。
#include <stdio.h>
typedef struct {
double x;
double y;
} point_t;
void
print_point(point_t point)
{
printf("%f,%f\n", point.x, point.y);
}
int
main(int argc, char *argv[])
{
point_t point;
point.x = 123.4;
point.y = 456.7;
print_point(point);
return 0;
}
としたいかもしれない。(まあ、これでも動く。)
しかし、C 言語の場合は、引数はコピーされて渡される。(値渡し)
構造体は複数の変数を束ねておりサイズが大きく、
コピー時間は、小さなプログラムであれば問題ないが、処理の量が多いと、かなりの時間になる。
そのため、通常はポインタ(=構造体の先頭アドレス)を渡すことが多いと思う。
#include <stdio.h>
typedef struct {
double x;
double y;
} point_t;
void
print_point(point_t *pointp)
{
printf("%f,%f\n", pointp->x, pointp->y);
}
int
main(int argc, char *argv[])
{
point_t point;
point.x = 123.4;
point.y = 456.7;
print_point(&point);
return 0;
}
リターン値を構造体にしたい場合はどうするのか
#include <stdio.h>
typedef struct {
double x;
double y;
} point_t;
void
print_point(point_t *pointp)
{
printf("%f,%f\n", pointp->x, pointp->y);
}
point_t
xy_point(double x, double y)
{
point_t point;
point.x = x;
point.y = y;
return point;
}
int
main(int argc, char *argv[])
{
point_t point;
point = xy_point(123.456, 789.123);
print_point(&point);
return 0;
}
としたいかもしれない。昔はコンパイルエラーだった。(と思う)
構造体をリターンすることができなかった。
今はコピーされてリターンするようだ。
昔ながらのやりかただと以下のようになる。
#include <stdio.h>
typedef struct {
double x;
double y;
} point_t;
void
print_point(point_t *pointp)
{
printf("%f,%f\n", pointp->x, pointp->y);
}
void
xy_point(double x, double y, point_t *ret)
{
point_t point;
ret->x = x;
ret->y = y;
}
int
main(int argc, char *argv[])
{
point_t point;
// point にリターン値を入れてもらうため、構造体へのポインタを渡す
xy_point(123.456, 789.123, &point);
print_point(&point);
return 0;
}
どのようにコンパイルされるか見たことがないので確信が無いが、
構造体自身をリターンできるのであれば、前者の方法でも良いかもしれない。