誰でも分かるC言語入門
■第7話:構造体と共用体
(最終更新日:2024.10.28)
(絵が小さい場合はスマホを横に)
「構造体と共用体を使おう」
今回は、C言語の高度なデータ構造である構造体と共用体について掘り下げる。
構造体は異なるデータ型を一つの複合体として扱うことができる強力なツールだ。
複雑なデータを効率的に管理するために広く利用されている。
一方、共用体は異なるデータ型を同一のメモリ領域に格納し、メモリの使用を最適化する特性を持つ。
これらのデータ構造を理解し、適切に使用することで、プログラムの柔軟性と効率が大幅に向上する。
本セッションでは、これらの概念の基礎から応用までを詳しく解説し、具体的な使用例を通じて学ぶ。
1.構造体の定義と使用
構造体は、C言語において異なるデータ型の変数を一つの単位でグループ化するための便利なツールだ。
これにより、複雑なデータをモジュール化し、管理が容易になる。
構造体は、データベースのレコードやオブジェクト指向プログラミングにおけるクラスに似た方法でデータを扱うことができる。
■構造体の定義
構造体はstructキーワードを使用して定義する。構造体定義は通常、データ型と同じように扱われるため、他の場所でこの型を再利用することができる。
下記の例では、Personという名前の構造体を定義し、それぞれchar配列、int、float型のデータを持つことを示している。
構造体の定義
構造体の変数宣言と初期化
加えて、構造体の型を使用して変数を宣言し、初期化することができる。
構造体の変数person1は、各メンバに個別にアクセスして値を設定する。
また、person2は宣言と同時に値を初期化している。
ここでいう変数はオブジェクト指向言語のclassでいうインスタンスのようなものだ。
構造体の初期化
■構造体と関数
構造体は関数に引数として渡すことができ、関数から戻り値としても返すことが可能だ。
これにより、複雑なデータ構造を関数間で効率的に扱うことができる。
下記の例では、printPerson関数はPerson型の引数を受け取り、その情報を出力している。
出力結果としては、Name: Carol、Age: 27、Height: 5.6がそれぞれ改行されて出る。
関数の引数に構造体を使用する
■構造体とポインタ
構造体を扱う際には、ポインタも一般的に使用される。
特に、大きな構造体を扱う場合や、動的なメモリ割り当てを使用する場合にポインタを利用すると効率的だ。
下記のように、ポインタpersonPtrを使用して構造体メンバにアクセスする場合は、アロー演算子(->)を使用する。
出力される結果は、person1で定義された値になるので「Alice is 30 years old」となる。
ポインタを用いて構造体を扱う
2.構造体と関数
構造体と関数の組み合わせは、C言語プログラミングにおいてデータをより効率的に管理し、操作するための強力な手法だ。
関数に構造体を渡すことで、データの一括処理が可能になり、コードの再利用性とモジュール性が向上する。
以下に、構造体を関数と組み合わせる方法と、その利点について詳しく説明する。
■構造体を関数に渡す方法
構造体を関数に渡すには、主に二つの方法がある。
1つ目は値渡しである。この方法は「構造体のコピーが関数に渡されるため、関数内での変更は元の構造体に影響を与えない」という特徴と
「大きな構造体を扱う場合、メモリの使用量が増加し、パフォーマンスが低下する可能性がある」という欠点がある。
値渡し
2つ目はポインタ渡しである。この方法は「ポインタを介して構造体のアドレスが渡されるため、メモリ効率が良く、関数内での変更が元の構造体に直接反映される」という特徴と 「ポインタを使用するため、間接的なアクセスが必要になるが、パフォーマンスの向上につながる」という利点がある。
ポインタ渡し
■構造体を関数から返す
C言語では、関数から構造体を返すこともできる。
これは、関数が新しいデータを生成したり、計算結果を構造体でまとめて返したりする場合に便利だ。
下記では、newPersonという構造体の変数を関数の結果として返している。
返り値に構造体を指定する
■構造体と関数の利点
- データのカプセル化:構造体を使用することで、関連するデータを一つの単位でまとめることができ、それによってデータをより意味のある形で扱うことが可能になる
- コードの再利用性と可読性の向上:関数を使って構造体の操作を行うことで、コードの重複を減らし、プログラムの可読性を向上させることができる
- 効率的なメモリ管理:ポインタを用いることで、大きなデータ構造を効率的に扱うことができる。値をコピーするのではなく、データのアドレスを渡すことでメモリ使用量が削減される
構造体と関数を組み合わせることで、プログラムがより構造的で、管理しやすく、効率的なものになる。 これはC言語における強力な抽象化手段の一つであり、大規模なプロジェクトや複雑なデータ処理において特に価値を発揮する。
3.共用体とその利用
共用体はC言語のデータ構造で、異なるデータ型の変数を同一のメモリ領域に格納するために使用される。 構造体と同じく、共用体も複数のメンバーを持つことができるが、共用体の全メンバーは同じメモリ位置を共有する。 これにより、異なるデータ型を同じメモリ領域で使い回すことが可能になり、メモリを効率的に利用することができる。
■共用体の定義と宣言
共用体はunionキーワードを使用して定義される。以下の例では、Dataという名前の共用体が定義されており、
整数型のi、浮動小数点型のf、そして20文字の文字列strをメンバーとして持っている。これらのメンバーは同じメモリ領域を共有する。
共用体の定義
■共用体の使用
共用体の変数を宣言し、そのメンバーにアクセスするには以下のように行う。
下記のコードでは、最初にdata.iに10を設定し、次にdata.fに220.5を設定し、最後にdata.strに"C Programming"をコピーしている。
各メンバーは同じメモリ領域を共有しているため、一つのメンバーを変更すると、それによって他のメンバーの値も影響を受ける可能性がある。
そのため、構造体とは異なり、デバッグ時に注意が必要だ。
共用体の設定と使用
■共用体の利点と用途
共用体の利点と用途を挙げる。第一にメモリの節約時に有用になる。異なるデータ型を同じメモリ領域で使えるからだ。
第二に、型安全ではない、異なるデータ型間でのビットレベルの操作を行う場合、共用体を使用して切り替えることができる。
例えば、浮動小数点表現と整数表現を同時に扱うことができる。
第三に、ハードウェアレジスタへのアクセスといった低レベルの操作で使うことができる。
共用体は特定の用途において非常に強力だが、その挙動を正しく理解し、適切に使用する必要がある。
誤った使用はデータの破損や意図しないバグを引き起こす原因となる。通常のケースでは構造体を使った方がよいだろう。
4.構造体とポインタ
C言語において構造体とポインタを組み合わせて使用することは一般的だ。これによりデータの効率的な管理や操作が可能になる。
構造体のポインタは、構造体のメモリアドレスを指し示し、このアドレスを通じて構造体のメンバにアクセスできる。
このアプローチは特に大きな構造体を扱う場合や、関数を通じて構造体のデータを操作する際に有効だ。
構造体におけるポインタの使い方、メンバへのアクセス、関数の引数としての使い方は既に上記で説明している。
そこで、ここでは、ダイナミックメモリの確保とポインタを通じた構造体の配列に関して説明する。
■ダイナミックメモリ確保
構造体のポインタと組み合わせて、malloc 関数を使用すると、実行時に構造体のメモリを動的に確保できる。
これにより、プログラムの柔軟性が向上する。
■ポインタを通じた構造体の配列
構造体のポインタは、構造体の配列を操作する際にも使用される。
配列の各要素に対してポインタ演算を行うことができる。
構造体の配列の操作
構造体とポインタを組み合わせることは、C言語で効率的なデータ構造を構築するための基本的な手法だ。 ポインタを利用することで、メモリ使用量を削減し、プログラムのパフォーマンスを向上させることができる。 また、関数を通じて構造体を効率的に操作する能力も高まる。
5.まとめ
今回は、C言語における構造体と共用体に焦点を当て、定義、使用方法、および適用例について学んだ。 構造体は異なるデータ型を一つのまとまりとして扱うことができ、プログラム内で複雑なデータ構造を簡単に管理するのに役立つ。 共用体は異なるデータ型を単一のメモリ領域に格納することで、メモリを効率的に使用するのに有効だ。 これらを利用することで、データの格納、処理、アクセス方法を最適化し、プログラムの効率とパフォーマンスを向上させることができる。
▼参考図書、サイト
「かんたん C言語」 大川内 隆朗 技術評論社
「12歳からはじめる ゼロからのC言語ゲームプログラミング教室」 リブロワークス