C言語集錦|03-C言語の複合データ型(typedefキーワード、構造体、列挙体、共用体)
ドキュメントのバージョン
更新時間
コンテンツの更新
v1.0
2020-09-14
初稿が完成する
文書ディレクトリ一、typedefキーワード 二、構造体(重点) 1. なぜ構造体 が必要なのか 2. 構造体 とは 3. 構造体 の定義方法 4. 構造体 の使用方法 4.1. 付与および初期化 4.2. 各メンバー へのアクセス 4.3. 構造体変数の演算 4.4. 構造体を関数として伝達する問題 5. 構造体メモリの位置合わせの問題(面接試験) 5.1. 問題の説明 5.2. 問題の原因 5.3. 問題解析 6. 構造体配列 6.1. 静的配列 6.2. 動的配列
三、列挙体 1. 列挙体 とは 2. 列挙体 の定義方法 3. 列挙体 の使用方法
4.コモン 1. 共用体 とは 2. なぜ共用体 が必要なのか 3. コモン を定義する方法 4. コモン の使用方法
一、typedefキーワード
typedefは、データ型に別名を付けるために使用されます.次のように使用されます.
例:
二、構造体(重点)
1.なぜ構造体が必要なのか
複雑なものを表すために、通常のデータ型は要求を満たすことができません.
2.構造体とは
いくつかの基本データ型を組み合わせて形成された新しいデータ型を構造体と呼ぶ.
3.構造体の定義方法
構造体を定義するには、次の4つの方法があります.
①データ型のみを定義し、変数は定義しない:
②データ型を定義し、変数を定義します.
③データ型を定義し、変数を定義しますが、構造体型は匿名です.
④データ型を定義し、変数を定義せず、同時に新しいタイプに別名を付ける(多用):
4.構造体の使い方
4.1. 割り当てと初期化
構造体変数には、定義と同時に初期値のみが付与されます.
定義が完了すると、全体的に値を割り当てることはできません.単一の値しか与えられません.
4.2. 各メンバーへのアクセス
構造体のメンバーにアクセスするには、次の2つの方法があります.は、構造体変数を介してメンバーにアクセスする. は、構造体変数を指すポインタによってメンバーにアクセスする.
①構造体変数によるアクセス:
②構造体変数へのポインタでアクセス:
4.3. 構造体変数の演算
構造体変数間では加算、減算、相互乗算はできませんが、構造体変数間では相互に値を割り当てることができます.
4.4. 構造体が関数として問題を伝達する
構造体を関数パラメータとして渡す場合は、次の2つの方法があります.直接構造体変数を伝達する:スタックのオーバーヘッドが大きく、関数では構造体の修正ができない. 構造体ポインタを直接渡します.4バイト(または8バイト)のポインタだけで、関数で構造体を変更できます. 5.構造体メモリの位置合わせの問題(面接試験)
5.1. 問題の説明
次のコードを実行します.
実行結果:
不思議なことに、構造体は25バイトを占有すべきではありませんか?なぜ28バイトなの?
st 1の各メンバーのアドレスを印刷するとわかります.
印刷結果:
sex変数はcharタイプで、もともと1バイトを占有すべきだったのに、実際には4バイトを占有していたことがわかります.
5.2. 問題の原因
コンパイラは、構造体の変数にスペースを割り当てるときにメモリ整列規則を使用します.
1構造体変数の開始アドレスは、その最も広いメンバーサイズで除去することができる.
②構造体の各メンバーの先頭アドレスに対するオフセットは、自身のサイズで割り切れるが、できない場合は、前のメンバーの後に空白バイトを補充する.
③構造体の全体的なサイズは、最も広いメンバーのサイズで除算できます.そうしないと、空白バイトが後で補充されます.
5.3. もんだいぶんせき
2番目のメンバsexはcharタイプであり、1バイトしか占有しないため、後のメンバscore定義の場合、自身のサイズは4であり、その結果、
これらの空白バイトを手動で補充すると、構造体全体のサイズは28バイトになります.
6.構造体配列
6.1. 静的配列
6.2. ダイナミック配列
三、列挙体
1.列挙体とは
列挙体は、1つのタイプの変数のすべての可能な値を羅列し、このタイプの変数に他の値を割り当てることはできません.
2.列挙体の定義方法
上記構造体の1つのメンバーはsex(性別)であり、列挙体を使用するのに適している.
列挙体を定義する方法は2つあります.
①列挙タイプのみ定義:
②列挙タイプを定義するとともに、新しい名前を付けて使いやすい.
3.列挙体の使用方法
まず、以前に定義した構造体を最適化します.
次に、sex変数に値を割り当てるときに使用します.
四.きょうようたい
1.共用体とは
共通体とは、複数の変数が同じメモリ空間を共有し、共通体の大きさは最大変数が占有するメモリ空間である.
2.なぜ共用体が必要なのか
最も典型的な使い方の一つは、構造体が差別化されていないことです.
たとえば、構造体があります.
使用状況は次のとおりです.賦値時には、1つのサイクルで賦値を遍歴することが要求され、メンバーの名前の違いを無視し、これを無差異化遍歴と呼ぶ. 使用時にメンバー名に従ってアクセスできることが要求される.
明らかに、最初の需要は配列を使用するのに適しており、2番目の需要は構造体を使用するのに適しているので、共通体を使用します.配列と構造体に同じメモリ空間を共有させます.
3.共通体の定義方法
上記の要件に従って共通体を定義し、新しい名前を付けます.この共通体が占有する空間は4つのintの大きさです.
4.共通体の使い方
値を割り当てるときに配列に従って使用し、最初の要件を満たすために直接ループします.
データにアクセスするときは、構造体に従って使用し、名前に従って値を取り、2番目の要件を満たします.
最終的な実行結果は次のとおりです.
更新時間
コンテンツの更新
v1.0
2020-09-14
初稿が完成する
文書ディレクトリ
一、typedefキーワード
typedefは、データ型に別名を付けるために使用されます.次のように使用されます.
typedef < > < >;
例:
typedef unsingned char uint8_t;
typedef unsingned int uint16_t;
二、構造体(重点)
1.なぜ構造体が必要なのか
複雑なものを表すために、通常のデータ型は要求を満たすことができません.
2.構造体とは
いくつかの基本データ型を組み合わせて形成された新しいデータ型を構造体と呼ぶ.
3.構造体の定義方法
構造体を定義するには、次の4つの方法があります.
①データ型のみを定義し、変数は定義しない:
struct student_st {
char name[20]; /* */
char sex; /* */
float score; /* */
};
②データ型を定義し、変数を定義します.
struct student_st {
char name[20]; /* */
char sex; /* */
float score; /* */
} st1;
③データ型を定義し、変数を定義しますが、構造体型は匿名です.
struct {
char name[20]; /* */
char sex; /* */
float score; /* */
} st1;
④データ型を定義し、変数を定義せず、同時に新しいタイプに別名を付ける(多用):
typedef struct student_st {
char name[20]; /* */
char sex; /* */
float score; /* */
} student_t;
4.構造体の使い方
4.1. 割り当てと初期化
構造体変数には、定義と同時に初期値のみが付与されます.
student_t st1 = {
"mculover666", 'M', 66.6};
定義が完了すると、全体的に値を割り当てることはできません.単一の値しか与えられません.
4.2. 各メンバーへのアクセス
構造体のメンバーにアクセスするには、次の2つの方法があります.
①構造体変数によるアクセス:
printf("name:%s sex:%c score:%.1f\r
", st1.name, st1.sex, st1.score);
②構造体変数へのポインタでアクセス:
student_t* st_ptr = &st1;
printf("name:%s sex:%c score:%.1f\r
", st_ptr->name, st_ptr->sex, st_ptr->score);
4.3. 構造体変数の演算
構造体変数間では加算、減算、相互乗算はできませんが、構造体変数間では相互に値を割り当てることができます.
student_t st1 = {
"mculover666", 'M', 66.6};
student_t st2;
st2 = st1;
printf("name:%s sex:%c score:%.1f\r
", st2.name, st2.sex, st2.score);
4.4. 構造体が関数として問題を伝達する
構造体を関数パラメータとして渡す場合は、次の2つの方法があります.
5.1. 問題の説明
次のコードを実行します.
printf("%d + %d + %d = %d", sizeof(st1.name), sizeof(st1.sex), sizeof(st1.score), sizeof(st1));
実行結果:
20 + 1 + 4 = 28
不思議なことに、構造体は25バイトを占有すべきではありませんか?なぜ28バイトなの?
st 1の各メンバーのアドレスを印刷するとわかります.
printf("st1: %p
st1.name: %p
st1.sex: %p
st1.score:%p
", &st1, &st1.name, &st1.sex, &st1.score);
印刷結果:
st1: 000000000061FDF0
st1.name: 000000000061FDF0
st1.sex: 000000000061FE04
st1.score:000000000061FE08
sex変数はcharタイプで、もともと1バイトを占有すべきだったのに、実際には4バイトを占有していたことがわかります.
5.2. 問題の原因
コンパイラは、構造体の変数にスペースを割り当てるときにメモリ整列規則を使用します.
1構造体変数の開始アドレスは、その最も広いメンバーサイズで除去することができる.
②構造体の各メンバーの先頭アドレスに対するオフセットは、自身のサイズで割り切れるが、できない場合は、前のメンバーの後に空白バイトを補充する.
③構造体の全体的なサイズは、最も広いメンバーのサイズで除算できます.そうしないと、空白バイトが後で補充されます.
5.3. もんだいぶんせき
2番目のメンバsexはcharタイプであり、1バイトしか占有しないため、後のメンバscore定義の場合、自身のサイズは4であり、その結果、
000000000061FE04+1
は整列規則を満たすことができないことが分かったので、空白バイトを補充し、前に20+4=24バイトがあるようにし、アドレスを000000000061FE08
に変更した.これらの空白バイトを手動で補充すると、構造体全体のサイズは28バイトになります.
typedef struct student_st {
char name[20]; /* */
char sex; /* */
char reserve_bytes[3]; /* */
float score; /* */
} student_t;
6.構造体配列
6.1. 静的配列
student_t st[100];
6.2. ダイナミック配列
#define STUDENT_NUM 100
/* */
student_t* st_ptr = (student_t *)malloc(STUDENT_NUM * sizeof(student_t));
/* ... */
/* */
free(st_ptr);
st_ptr = NULL;
三、列挙体
1.列挙体とは
列挙体は、1つのタイプの変数のすべての可能な値を羅列し、このタイプの変数に他の値を割り当てることはできません.
2.列挙体の定義方法
上記構造体の1つのメンバーはsex(性別)であり、列挙体を使用するのに適している.
列挙体を定義する方法は2つあります.
①列挙タイプのみ定義:
enum student_sex_en {
MALE = 'M',
FAMALE = 'F',
};
②列挙タイプを定義するとともに、新しい名前を付けて使いやすい.
typedef enum student_sex_en {
MALE = 'M',
FAMALE = 'F',
} student_sex_t;
3.列挙体の使用方法
まず、以前に定義した構造体を最適化します.
typedef struct student_st {
char name[20]; /* */
student_sex_t sex; /* */
char reserve_bytes[3]; /* */
float score; /* */
} student_t;
次に、sex変数に値を割り当てるときに使用します.
student_t st1 = {
"mculover666", MALE, 66.6};
四.きょうようたい
1.共用体とは
共通体とは、複数の変数が同じメモリ空間を共有し、共通体の大きさは最大変数が占有するメモリ空間である.
2.なぜ共用体が必要なのか
最も典型的な使い方の一つは、構造体が差別化されていないことです.
たとえば、構造体があります.
typedef struct num_st {
int a;
int b;
int c;
int d;
} num_t;
使用状況は次のとおりです.
明らかに、最初の需要は配列を使用するのに適しており、2番目の需要は構造体を使用するのに適しているので、共通体を使用します.配列と構造体に同じメモリ空間を共有させます.
3.共通体の定義方法
上記の要件に従って共通体を定義し、新しい名前を付けます.この共通体が占有する空間は4つのintの大きさです.
typedef union num_un {
num_t num;
int n[4];
} num_u;
4.共通体の使い方
値を割り当てるときに配列に従って使用し、最初の要件を満たすために直接ループします.
num_u num1;
for (int i = 0; i < 4; i++) {
num1.n[i] = i;
}
データにアクセスするときは、構造体に従って使用し、名前に従って値を取り、2番目の要件を満たします.
printf("a = %d, b = %d, c = %d, d = %d\r
", num1.num.a, num1.num.b, num1.num.c, num1.num.d);
最終的な実行結果は次のとおりです.
a = 0, b = 1, c = 2, d = 3