C言語の基礎 |
6-1 構造体
構造体とは、intやcharなどのデータ型を組み合わせて新しいデータ型として扱うことである。例えば、生徒の氏名、出席番号と電話番号を扱う場合、次のように変数を設定するのが基本的なやり方である。
char name[20];
int number;
int tel;
しかし、これらのデータは1人分のデータであるから必ずまとめて処理されるます。 したがって、これらを1つのデータとして扱うことができると便利であるから、新しいデータ型を作ることにする。新しいデータ型の名前は、newtype(名前は自由につけることができる)とする。このnewtypeの宣言は次のようになる。
struct newtype {
char name[20];
int number;
int tel;
};
ここで、structが新しい型を定義するための命令である。このnewtypeという型を持つ変数を構造体変数といい、宣言するには次のようにする。構造体変数名はseitoとする。
struct newtype seito;
構造体変数seitoにはname, number, telという要素が含まれている。
/* sample48.c */ #include <stdio.h> #include <stdlib.h> int main(void) { struct newtype{ /* ← 新しい型の定義 *1 */ char name[20]; int number; int tel; }; struct newtype seito; /* ← 新しい型の構造体変数の宣言 */ char buff[80]; printf("Name="); gets(seito.name); /* ← 要素の使用 */ printf("Number="); gets(buff); seito.number = atoi(buff); printf("Tel="); gets(buff); seito.tel = atoi(buff); printf("No%d %s (%d)\n",seito.number, seito.name, seito.tel); }
新しい型の各要素を参照するには、構造体変数名と各要素名をピリオドでつなぐ。もし、40人分の変数を用意したければ、新しい型の宣言で次のように配列として宣言する。
struct newtype seito[40];
例えば5番目の生徒のデータを参照したい場合は、次のようにする。
seito[5].name, seito[5].number, seito[5].tel
C言語では新しいデータ型をタグといい、各要素のことをメンバという。
(1) 構造体の宣言方法
構造体の定義・宣言方法には次のような種類がある。
@ タグ(新しいデータ型)の定義
struct タグ名 {メンバの並び}; A 構造体変数の宣言
struct タグ名 構造体変数名; B @,Aを同時に行う
struct タグ名 {メンバの並び} 構造体変数名; C タグの定義を行わないで構造体変数の宣言を行う
struct {メンバの並び} 構造体変数名;
sample48.c の例では、@とAの方法で構造体を利用している。
Bの方法を使用すると*1の部分は次のようになる。
struct newtype {
name[20];
number;
tel;
} seito;
また、Cの方法を使用すると*1の部分は次のようになる。
struct {
name[20];
number;
tel;
} seito;
(2) 構造体メンバーの参照
構造体の各メンバーを利用するには、sample48.cにも示したように構造体変数名とメンバー名をピリオドでつないで使用する。
構造体変数名.メンバー名
構造体変数も変数であるからポインタとして扱うこともできる。
/* sample49.c */
#include <stdio.h>
int main(void)
{
struct xyz {
int i;
int j;
};
struct xyz abc, *pabc;
pabc = &abc;
pabc->i = 10;
pabc->j = 20;
printf("abc.i=%d abc.j=%d\n", pabc->i, pabc->j);
}
構造体ポインタ変数でメンバを参照する場合には、ポインタ変数とメンバ名を->でつないで使用する。
構造体のポインタ変数名->メンバ名
メモリには次のように領域が確保される。
(3) 構造体のデータ一括代入
ANSI C規格で正式に認められた処理である。今までのC言語では、構造体の各メンバのデータを代入するには、それぞれ個別に行わなければならなかった。
struct {
int i;
int j;
} a, b;
このような場合、構造体変数bのデータを構造体変数aに代入するには次のようにメンバ個別に行った。
a.i = b.i;
a.j = b.j;
ANSI Cでは、構造体変数名どうしの代入が可能になった。上と同じ処理を次のように書くことができる。
a = b;
(4) 関数での構造体データの受け渡し
他の変数と同じように、構造体変数を関数の引数及び返却値に指定することができる。
/* sample50.c */ #include <stdio.h> struct date { /* ← 構造体の定義 */ int year; int month; int day; }; int main(void) { struct date nextday(struct date); /* ← 関数の宣言 */ struct date today, tomorrow; /* ← 構造体変数の宣言 */ today.year = 1992; today.month = 5; today.day = 17; tomorrow = nextday(today); /* ← 関数の呼び出し */ printf("%d/%d/%d\n",tomorrow.year, tomorrow.month, tomorrow.day); } struct date nextday(struct date now) /* ← 構造体データを引数として受け取る */ { struct date next; next = now; next.day += 1; return(next); /* ← 構造体データを返す */ }
関数nextdayでは、struct date型の構造体変数を引数と返却値に利用している。
(5) フィールド
変数に1か0の情報を持たすだけのためにshort型の変数を使うとそれだけでメモリを2バイト使ってしまう。情報としては1か0の1ビットであるからうまく利用すれば、short型の変数で16個の1か0の情報を格納する個とができる。これを行うのがフィールドである。
/* sample51.c */
#include <stdio.h>
struct {
unsigned a: 1;
unsigned b: 1;
unsigned c: 1;
} flag;
int main(void)
{
flag.a = 1;
flag.b = 0;
flag.c = 1;
printf("a=%d b=%d c=%d\n",flag.a, flag.b, flag.c);
}
フィールドの定義は構造体と同じである。メンバーのところでビット幅を指定するのが違うところである。
フィールド(メンバー)名:ビット幅 |
6-2 共用体
1つの共通領域を違ったデータ型として取り扱うことができる。
union tagname
short a;
char b;
int c;
} xyz;
共用体の定義には、unionを使う。定義方法は構造体と同じである。
上の場合メモリには、次のように領域が確保される。
各データの参照方法も構造体と同じである。
6-3 列挙型
定義・宣言の方法は構造体と同じである。structの代わりにenumを使う。
enum number {ZERO, ONE, TWO, THREE} num;
ZERO, ONE, TWO, THREE はそれぞれ列挙型定数である。それぞれ値としてZERO=0,
ONE=1, TWO=2, THREE=3を持っている。
最初の列挙型定数の値を0として、それ以降は1ずつ増えていく。また次のように値を定義することもできる。
enum number {ZERO, FIVE=5, SIX, SEVEN} num;
それぞれ、ZERO = 0, FIVE = 5, SIX = 6, SEVEN = 7 の値を持つ。
Copyright © 2001 Hiroshi Masuda |