C言語 構造体
C言語改訂版1 はじめてのプログラミング (CD-ROM付) (プログラミング学習シリーズ)
- 作者: 倉薫
- 出版社/メーカー: 翔泳社
- 発売日: 2009/02/13
- メディア: 大型本
- 購入: 3人 クリック: 14回
- この商品を含むブログ (3件) を見る
構造体とは、
様々な型の複数のデータをまとめて、1つの型のように扱うもの
という理解。個体に紐づけて様々な情報を管理したいときに使う「型を柔軟にした変数」という理解。
簡単に書いてみた。構造体については、本よりもこっちの方がわかりやすかった。
(本は、display関数についての解説が不可解)
まず、ヘッダーファイルで構造体を定義(さまざまなファイルからのアクセスが想定される構造体はヘッダーファイルに残す)。構造体の定義時は
struct タグ名 {構造体の中身};
とするらしい。タグ名という名称が初めて出てきた。
//Person.h struct Person { //個人情報を格納する構造体Personを定義(※架空)。struct タグ名 という形で書く(今回ならPersonがタグ名) int ID; //ID int birthday; //誕生年,月,日 char pref[30]; //居住都道府県 char postalcode[30]; //郵便番号 char sex[30]; //性別 char name[30]; //名前 int income; //年収 };
…で、本編で構造体の要素を入力する。下記、構造体を表す変数を、
struct タグ名 構造体変数名[要素数] = { { }, { }, { }, …}
という形で定義している。
//strc.c
#include <stdio.h> #include "Person.h" //ヘッダーファイルから構造体の定義を読込 main () { int i = 0; printf("ID\tBrithday\tPref\tPostalcode\tSex\tName\t\tIncome\n"); //表示時の項目名。タブ(\t)を使うと表示が綺麗に struct Person A[3] = { //構造体の初期化。3は入力する構造体の要素数。 1 {1, 19801203, "Tokyo", "160-0012", "Male", "Tanaka Taro", 600}, {2, 19830228, "Kyoto", "606-8243", "Female", "Sato Hanako", 1000}, {3, 19480831, "Chiba", "277-0291", "Male", "Takahashi Jiro", 800}, }; //順にID,誕生年月日,居住都道府県,郵便番号,性別,名前,年収 for(i = 0; i < 3; i++) { //入力した構造体を表示 printf("%d\t%d\t%s\t%s\t%s\t%s\t%d\n", A[i].ID, A[i].birthday, A[i].pref, A[i].postalcode, A[i].sex,A[i].name, A[i].income); } return 0; //終了宣言 }
gcc strc.c でコンパイル後、./a.exeを実行。出力はこんな感じになった。
ID Brithday Pref Postalcode Sex Name Income
1 19801203 Tokyo 160-0012 Male Tanaka Taro 600
2 19830228 Kyoto 606-8243 Female Sato Hanako 1000
3 19480831 Chiba 277-0291 Male Takahashi Jiro 800
---------------------------------------------------------------------------------------------------------------
変数と同様、構造体はポインタとセットで使えるとなお良い。確かポインタ変数は、メモリの住所の受け皿(住所を与えることで住所の先にある変数に対して処理を行うための変数)という理解をしていた。
ポインタ変数使うときは、
ポインタ変数 = 変数の住所 (&変数名 で表す) もしくは
形でポインタ変数に住所を与えていた。
同様にして、構造体ポインタ変数についても、
構造体ポインタ変数 = 構造体変数の住所 (&構造体変数名 で表す) もしくは
構造体ポインタ変数で定義した関数の引数に構造体変数の住所を書き込む
という形で使えば良い、ということか。ところで、変数を配列で定義している場合は、&で住所を指定する必要はないのだった。配列の先頭が住所に対応することになる。だから、次のように書けばよい。
#include <stdio.h> #include "Person.h" main () { int i = 0; printf("ID\tBrithday\tPref\tPostalcode\tSex\tName\t\tIncome\n"); struct Person A[3] = { {1, 19801203, "Tokyo", "160-0012", "Male", "Tanaka Taro", 600}, {2, 19830228, "Kyoto", "606-8243", "Female", "Sato Hanako", 1000}, {3, 19480831, "Chiba", "277-0291", "Male", "Takahashi Jiro", 800}, }; struct Person *p; //構造体ポインタ変数pの定義 p = A; //構造体ポインタ変数にAの住所を与える(&A[0]の省略形) for(i = 0; i < 3; i++) { printf("%d\t%d\t%s\t%s\t%s\t%s\t%d\n", (p+i)->ID, (p+i)->birthday, (p+i)->pref, (p+i)->postalcode, (p+i)->sex,(p+i)->name, (p+i)->income); } return 0; }
ただし、構造体ポインタ変数を用いて構造体の要素(住所とか)にアクセスするときは、
(ポインタ構造体変数) -> 要素名
とするらしい。この理解でよいのだろうか。とりあえず先に進む。
【追記】
本に載っていた演習問題の解説で発見があったのでメモ。
- 構造体同士の代入は可能である。(構造体変数 = 構造体変数 のように書いて良いということ) ⇒ 文字列の場合は、strcpy()を使わなくてはならなかったので、文字列を含む構造体変数では直接代入出来るのは意外。
- 構造体はそれ自体を他の関数への引数として渡すことが認められている。 ⇒ 配列はそれ自体を他の関数への引数として渡すことはできなかった(※NKさんのナイスなコメント参照)。なのに、構造体では出来るのは何故か。