[構造体] とは, 複数の変数を一つのファテゴリ, ユニットにしたものである. 例えば, 文献リストの作成を考えてみよう:
char author[40]; /* 著者 */
char title[80]; /* タイトル */
int year; /* 発行年 */
char resource[120]; /* 出典元 */
構造体型オブジェクトを作成するには:
struct タグ{struct-宣言}
struct タグ
のいずれかを使用する. struct-宣言には, 構造体タグがもつ [メンバ] のリストを指定する. 例えば, 文献リストの場合, 次のように宣言すれば:
struct ref{
char author[40]; /* 著者 */
char title[80]; /* タイトル */
int year; /* 発行年 */
char resource[120]; /* 出典元 */
};
オブジェクト変数を宣言したいときに, 下の例を使う:
struct ref{
char author[40]; /* 著者 */
char title[80]; /* タイトル */
int year; /* 発行年 */
char resource[120]; /* 出典元 */
};
struct ref paper, book;
宣言の文法に従えば, 構造体 ref 型とオブジェクトを同時に指定することもできる:
struct ref{
char author[40]; /* 著者 */
char title[80]; /* タイトル */
int year; /* 発行年 */
char resource[120]; /* 出典元 */
}paper, book;
構造体を初期化する:
struct ref{
char author[40]; /* 著者 */
char title[80]; /* タイトル */
int year; /* 発行年 */
char resource[120]; /* 出典元 */
}paper = {
"J. von Neumann",
"Zur Theorie der Gesellschaftsspiele",
1928,
"Mathematische Annalen"
};
struct ref book = {
"J. von Neumann and O. Morgenstern",
"Theory of Games and Economic Behavior",
1944,
"Princeton University Press"
};
構造体オブジェクトはメンバを持ち, メンバを参照するための演算子は [メンバ演算子] と [ポインタ] 演算子 の2つがある. ここでは, メンバ演算子を見る.
メンバ演算子 (Member Operator):
構造体型オブジェクト.メンバ名
member_op.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <stdio.h>
struct ref{
char author[40]; /* 著者 */
char title[80]; /* タイトル */
int year; /* 発行年 */
char resource[120]; /* 出典元 */
};
int main(void){
struct ref paper = {
"J. von Neumann",
"Zur Theorie der Gesellschaftsspiele",
1928,
"Mathematische Annalen"
};
printf("[AU] %s\n", paper.author);
printf("[TI] %s\n", paper.title);
printf("[YR] %d\n", paper.year);
printf("[SO] %s\n", paper.resource);
return 0;
}
|
member_op.c の実行結果は:
[cactus:~/code_c/c_tuts]% ./member_op
[AU] J. von Neumann
[TI] Zur Theorie der Gesellschaftsspiele
[YR] 1928
[SO] Mathematische Annalen
member_op2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h>
struct s{
char c;
double r[3];
}x = {
'A',
{1.5, -3.0, 2.0}
};
int main(void){
printf("c\tr[0]\t\tr[1]\t\tr[2]\n");
printf("%c\t%f\t%f\t%f\n", x.c, x.r[0], x.r[1], x.r[2]);
return 0;
}
|
member_op2.c の実行結果は,
c r[0] r[1] r[2]
A 1.500000 -3.000000 2.000000
struct_array.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <stdio.h>
#include <string.h>
struct ref{
char author[40]; /* 著者 */
char title[80]; /* タイトル */
int year; /* 発行年 */
char resource[120]; /* 出典元 */
}paper[100], book[100];
int main(void){
memcpy(paper[0].author, "J. von Neumann", sizeof(paper[0].author) - 1);
memcpy(paper[0].title, "Zur Theorie der Gesellschaftsspiele", sizeof(paper[0].title) - 1);
paper[0].year = 1928;
memcpy(paper[0].resource, "Mathematische Annalen", sizeof(paper[0].resource) - 1);
printf("[AU] %s\n", paper[0].author);
printf("[TI] %s\n", paper[0].title);
printf("[YR] %d\n", paper[0].year);
printf("[SO] %s\n", paper[0].resource);
return 0;
}
|
struct_array.c の実行結果は:
[cactus:~/code_c/c_tuts]% ./struct_array
[AU] J. von Neumann
[TI] Zur Theorie der Gesellschaftsspiele
[YR] 1928
[SO] Mathematische Annalen
struct_array2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <stdio.h>
struct s{
int n;
char str[12];
}x[100] = {
{ 1, "first" },
{ 2, "second" },
{ 3, "third" },
{ 4, "Fouth" },
{ 5, "Fifth" }
};
int main(void){
int i;
for(i = 0; x[i].n != 0; i++)
printf("x[%d] %d\t%s\n", i, x[i].n, x[i].str);
return 0;
}
|
struct_array2.c の実行結果は:
[cactus:~/code_c/c_tuts]% ./struct_array2
x[0] 1 first
x[1] 2 second
x[2] 3 third
x[3] 4 Fouth
x[4] 5 Fifth
struct_struct.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <stdio.h>
#include <string.h>
struct ref{
char author[40]; /* 著者 */
char title[80]; /* タイトル */
int year; /* 発行年 */
char resource[120]; /* 出典元 */
};
struct list{
char class[32];
struct ref paper[100]; /* 構造体の構造体 */
}list;
int main(void){
memcpy(list.class, "Game Theory", sizeof(list.class)-1);
memcpy(list.paper[0].author, "J. von Neumann", sizeof(list.paper[0].author)-1);
memcpy(list.paper[0].title, "Zur Theorie der Gesellschaftsspiele", sizeof(list.paper[0].title)-1);
memcpy(list.paper[0].resource, "Mathematische Annalen", sizeof(list.paper[0].resource)-1);
list.paper[0].year = 1928;
printf("[AU] %s\n", list.paper[0].author);
printf("[TI] %s\n", list.paper[0].title);
printf("[YR] %d\n", list.paper[0].year);
printf("[SO] %s\n", list.paper[0].resource);
printf("[FI] %s\n", list.class);
return 0;
}
|
struct_struct.c の実行結果は:
[cactus:~/code_c/c_tuts]% ./struct_struct
[AU] J. von Neumann
[TI] Zur Theorie der Gesellschaftsspiele
[YR] 1928
[SO] Mathematische Annalen
[FI] Game Theory
struct_struct2.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <stdio.h>
struct s{
char c;
char str[12];
};
struct st{
int n;
struct s x;
}y[20] = {
{ 1, {'a', "first" } },
{ 2, {'b', "second" } },
{ 3, {'c', "third" } }
};
int main(void){
int i;
for(i = 0; y[i].n != 0; i++)
printf("y[%d] %d %c %s\n", i, y[i].n, y[i].x.c, y[i].x.str);
return 0;
}
|
struct_struct2.c の実行結果は:
[cactus:~/code_c/c_tuts]% ./struct_struct2
y[0] 1 a first
y[1] 2 b second
y[2] 3 c third
ポインタ演算子 (Pointer Operator):
ポインタ->メンバ名
pointer_arith.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <stdio.h>
#include <string.h>
struct s{
char n;
char str[12];
}x[20] = {
{ 1, "first" },
{ 2, "second" },
{ 3, "third" }
};
int main(void){
struct s *p;
for(p = x; (p->n) != 0; p++)
printf("x[%td] %d %s\n", p-x, p->n, p->str);
p->n = 4;
memcpy(p->str, "fourth", sizeof(p->str)-1);
printf("x[%td] %d %s\n", p-x, p->n, p->str);
return 0;
}
|
pointer_arith.c の実行結果は:
[cactus:~/code_c/c_tuts]% ./pointer_arith
x[0] 1 first
x[1] 2 second
x[2] 3 third
x[3] 4 fourth
構造体のメンバに自己へのポインタが入っている構造体を [自己参照型構造体] (自己参照構造体, Self-Referential Structure) という.
self_struct.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <stdio.h>
struct s{
int n;
struct s *p;
}x, *a;
int main(void){
a = &x;
a->n = 1;
printf("(1) x.n = %d\t[%p]\n", x.n, &(x.n));
/* &x.n = &(x.n) */
/* &(x.n) = &(a->n) */
printf("(2) x.p \t[%p]->", x.p);
a->p = a;
printf("[%p]\n", x.p);
x.p->n = 2;
printf("(3) x.n = %d\t[%p]\n", x.n, &(x.n));
return 0;
}
|
self_struct.c の実行結果は:
[cactus:~/code_c/c_tuts]% ./self_struct
(1) x.n = 1 [0x100001080]
(2) x.p [0x0]->[0x100001080]
(3) x.n = 2 [0x100001080]
list.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct list{
int n;
char str[12];
struct list *next;
};
struct list *createData(int num, char *word);
/* 返却値が struct list * 型の関数 */
int main(void){
int i; // インクリメント用
char *keywords[10] = {
"\\0",
"if",
"while",
"for",
"do",
"switch",
"case",
"break",
"int",
"char"
};
struct list *head, *new, *data;
/*
struct list *head は リストの先頭アドレスを保存ている.
struct list *new は リストの一個一個の基本要素構造体へのアドレスを次々と保存している.
struct list *data は 各構造体のつながりをして, リスト構造に構成させる.
*/
head = createData(0, keywords[0]); // "\\0" をリストに入れる
data = head;
for(i = 1; i< 10; i++){
new = createData(i, keywords[i]);
data->next = new;
data = new;
}
printf("[Address]\tn\tstr\tnext\n");
for(data = head; data != NULL; data = data->next)
printf("[%p]\t%d\t%s\t%p\n", data, data->n, data->str, data->next);
/*
リストを出力する
*/
return 0;
}
struct list *createData(int num, char *word){
struct list *data; // この構造体はローカル関数内だけ使える.
data = (struct list *)malloc(sizeof(struct list));
if(data == NULL)
exit(1);
data->n = num;
memcpy(data->str, word, sizeof(data->str)-1);
data->next = NULL; // すべての構造体をそれぞれ繋がっていないために, NULL で初期化する.
return data;
}
|
list.c の実行結果は:
[Address] n str next
[0x100100080] 0 \0 0x1001000a0
[0x1001000a0] 1 if 0x1001000c0
[0x1001000c0] 2 while 0x1001000e0
[0x1001000e0] 3 for 0x100100100
[0x100100100] 4 do 0x100100120
[0x100100120] 5 switch 0x100100140
[0x100100140] 6 case 0x100100160
[0x100100160] 7 break 0x100100180
[0x100100180] 8 int 0x1001001a0
[0x1001001a0] 9 char 0x0