目次
構造体
構造体とは何か?
なぜC言語に構造体が導入されたのか?
構造体型の宣言
構文構造
練習問題
構造体メンバの型
構造体変数の定義
構造体の初期化
構造体メンバへのアクセス
構造体の関数渡し
構造体
今年の立秋は早かったですね。皆さんは初めての秋のカフェオレを飲めましたか?今日は構造体について詳しく説明します。この記事では基本的な内容を扱い、今後の詳細な解説につなげていきます。
構造体とは?
構造体は複数の値をまとめるデータ型であり、それぞれの値は「メンバ」と呼ばれます。各メンバは異なる型を持つことができます。
C言語に構造体が導入された理由
C言語にはintやchar、doubleなどの基本型がありますが、これらは単一の情報を表現するだけです。複雑なオブジェクトを表現するには不十分です。たとえば、「人」を表現する場合、性別、年齢、身長、体重など複数の情報を同時に扱う必要があります。このような場合に構造体が役立ちます。
構造体型の宣言
構文構造
struct タグ名
{
メンバリスト;
} 変数リスト;
structキーワードは省略できませんタグ名 独自に定義した構造体名(実際の用途に応じて命名)
メンバリスト メンバ変数の一覧
変数リスト 変数の一覧
練習問題
ここでは学生情報の構造体を作成してみましょう。
//学生型------→学生変数--------→学生の属性情報
#include <stdio.h>
struct Student
{
char name[10];
char gender[5];
int age;
};
int main()
{
return 0;
}
構造体メンバの型
構造体のメンバには様々な型が使用できます。スカラー値、配列、ポインタ、他の構造体なども可能です。
struct Student
{
int id; // スカラー値
char name[10]; // 配列
char gender[5];
int* ptr; // ポインタ
struct Class; // 他の構造体
struct Class* cptr; // 構造体ポインタ
};
int main()
{
return 0;
}
構造体変数の定義
グローバル変数、ローカル変数、別名による定義方法があります。
// グローバル・ローカル変数
#include <stdio.h>
struct Student
{
char name[10];
char gender[5];
int age;
}s3, s4; // s3, s4 はグローバル変数
struct Student s5; // s5 もグローバル変数
int main()
{
struct Student s1;
struct Student s2;
// s1, s2 はローカル変数
return 0;
}
// 別名による定義
#include <stdio.h>
typedef struct Student
{
char name[10];
char gender[5];
int age;
} STUDENT;
int main()
{
struct Student s1;
struct Student s2;
// 別名を使った定義も可能
STUDENT s6; // ローカル変数
return 0;
}
構造体の初期化
初期化方法には「順序による初期化」と「特定メンバによる初期化」の2種類があります。
上記「構造体変数の定義」で紹介したすべての方法に適用可能です。
#include <stdio.h>
struct InnerStruct
{
int key;
};
struct OuterStruct
{
char ch;
int value;
int array[10];
double* ptr;
struct InnerStruct inner;
struct InnerStruct* iptr;
};
int main()
{
double val = 3.14;
// 順序による初期化
struct OuterStruct s3 = { 'q', 100, {1,2,3,4}, &val, {99}, NULL };
// 特定メンバによる初期化
struct OuterStruct s4 = { .value = 1000, .array = {1,2,3,4,5} };
// 部分的に初期化され、残りはゼロクリア
return 0;
}
構造体メンバへのアクセス
.構造体.メンバ->構造体->メンバ
#include <stdio.h>
struct Book
{
char title[20];
int cost;
};
void print_info(struct Book b)
{
printf("%s %d\n", b.title, b.cost);
}
void print_ptr(struct Book* pb)
{
printf("%s %d\n", (*pb).title, (*pb).cost);
printf("%s %d\n", pb->title, pb->cost);
}
int main()
{
struct Book book = { "C言語入門", 55 };
print_info(book); // 値渡し
print_ptr(&book); // アドレス渡し
printf("%s %d\n", book.title, book.cost);
struct Book* ptr = &book;
printf("%s %d\n", ptr->title, ptr->cost); // ポインタと組み合わせる
return 0;
}
構造体の関数渡し
練習:構造体sにデータを設定する関数を作成してください。
#include <stdio.h>
#include <string.h>
struct Data
{
char name[20];
int age;
};
void set_data(struct Data t) // 値渡し
{
t.age = 18;
strcpy(t.name, "zhangsan");
// t.name = "zhangsan"; ❌ 配列名は定数のアドレスなので代入不可
}
int main()
{
struct Data s = { "name", 0 };
set_data(s);
printf("%s %d\n", s.name, s.age);
return 0;
}
なぜsにデータが保存されなかったのでしょうか?これは以前の配列と関数の交換処理で学んだ内容と同じです。
実引数から仮引数へ渡されるとき、仮引数は実引数のコピーであり、仮引数の変更は実引数に影響しません。
よって、関数内で実引数を変更したい場合は、そのアドレスを渡す必要があります。
#include <stdio.h>
#include <string.h>
struct Data
{
char name[20];
int age;
};
void set_data(struct Data* t) // アドレス渡し
{
t->age = 19;
strcpy(t->name, "zhangsan");
}
int main()
{
struct Data s = { "name", 0 };
set_data(&s); // 実引数としてアドレスを渡す
printf("%s %d\n", s.name, s.age);
return 0;
}
関数呼び出し時に変数を渡すか、アドレスを渡すかはどのように選択すべきでしょうか?
アドレス渡しを選ぶべきです
関数に引数を渡す際、スタックに積まれる必要があります。
構造体が大きい場合、スタックへの積み込みが大きくなり、パフォーマンスが低下します。
構造体を関数に渡す際は、アドレスを渡すのが望ましいです。
✔✔✔最後に、ご閲覧ありがとうございました。間違いや改善点があれば、ご指摘いただけますと幸いです!🙂
コード---------------------→【gitee:https://gitee.com/TSQXG】
連絡---------------------→【メール:2784139418@qq.com】