記事ディレクトリ
構造
C には、構造体と配列の 2 つの集計データ型があります。
配列に格納されている各要素は同じ型ですが、構造体は異なる型を格納できます。構造体の各要素はメンバーと呼ばれ、各メンバー型は異なる場合があります。
配列名とは異なり、構造体変数は式で使用されたときにポインターに置き換えられず、構造体変数は添字を使用してメンバーを選択することはできません。
変数の宣言と作成
struct tag //类型tag
{
member-list} //成员列表
variable_list; //变量列表
このステートメントはオブジェクトを作成しません。つまり、データ用の領域は割り当てられません。オブジェクトの構造レイアウトを説明するだけです。
//声明一个struct tag,但是未创建变量,所以不占用空间
struct book {
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
//创建变量
struct book lib;
struct book libs[10];
typedef 宣言を使用することは、優れた手法です。
//此声明方式与上面类似,但是使用了typedef关键字,把类型struct BOOK_TAG重命名为Book
//此处的BOOT_TAG可以省略,也就是直接使用Book作为别名
typedef struct BOOK_TAG{
char title[MAXTITL];
char author[MAXAUTL];
float value;
} Book; //注意这里的Book不是创建变量,而是别名
//创建结构变量时可以省略struct关键字了
Book x;
Book y[20];
変数を作成する簡単な方法
//结构声明并创建变量
struct book {
char title[MAXTITL];
char author[MAXAUTL];
float value;
} lib;
タグを宣言せずに変数を直接作成することもできます
//创建了一个lib的变量里面包含三个成员
struct {
char title[MAXTITL];
char author[MAXAUTL];
float value;
} lib;
//声明一个数组,他包含10个结构。
struct {
char title[MAXTITL];
char author[MAXAUTL];
float value;
} libs[10];
//声明一个指针,指向该结构,注意这里只创建了个指针,并没有指向谁
struct {
char title[MAXTITL];
char author[MAXAUTL];
float value;
} *l;
構造体メンバー
構造体のメンバーは、スカラー、配列、ポインター、およびその他の構造体にすることができます
//创建了一个lib的变量里面包含三个成员
struct {
int a;
int b[23];
long *lp;
struct Simple s;
} lib;
自己参照構造
次の自己参照は不正です, なぜなら, member s は別の完全な構造体であり, 内部に独自の member s を含みます.サイズを計算できないため、違法です。
struct Simple {
int a;
struct Simple s;
flaot b;
};
次のステートメントはポインターであり、長さを直接計算できるため、有効です。
struct Simple {
int a;
struct Simple *p;
flaot b;
};
自己参照トラップ
typdefs を使用して構造体を宣言するとき、宣言することを期待します
typedef struct {
int a;
Simple *p;
flaot b;
} Simple;
しかし、宣言の最後まで型名が定義されておらず、構造体が宣言されたときに型名が定義されていないため、失敗します。
解決策の 1 つは、タグを省略しないことです。
typedef struct Simple_TAG{
int a;
struct Simple_TAG *p;
flaot b;
} Simple;
構造の相互参照
struct B; //不完整声明
struct A {
float value;
struct B *pb;
};
struct B {
float value;
struct A *pb;
};
初期化
struct {
char title[MAXTITL];
char author[MAXAUTL];
float value;
} lib;
//创建变量并初始化
struct book lib = {
"Garlic-Melon Bank",
"Lucky's Savings and Loan",
8543.94
};
//这种方式可以调换每个成员的顺序
struct book lib2 = {
.value = 8543.94,
.author = "Garlic-Melon Bank",
.title = "Lucky's Savings and Loan"
};
構造体メンバーへのアクセス
struct COMPLEX {
char *name;
int age;
};
struct COMPLEX comp; //声明变量
comp.age = 4;
struct COMPLEX *c = ∁ //声明指针
c->age = 5;
割り当て
配列では、ある配列を別の配列に割り当てることはできません
int a[3] = {
1,4,5};
int b[3];
b = a; //这是不允许的
しかし、構造体はできます
struct namect {
char fname[NLEN];
char lname[NLEN];
int letters;
};
struct namect a = {
"asndg", "ang", 4};
struct namect b = a; //这是允许的,是把a的每个成员的值都给b,并且其中的数组的值也可以完全拷贝过去。
ディープコピーとシャローコピー
ただし、構造体にポインタ変数が含まれており、構造体の使用中に動的メモリ割り当てが実行され、同じ型の構造体の変数が同時に割り当てられると、シャロー コピーとディープ コピーの問題が発生します。 .
浅いコピー
typedef struct Student
{
char *name;
int age;
}Student;
int main(int argc, char *argv[])
{
Student std1;
Student std2;
//给结构体1赋值并打印
std1.name = (char *)malloc(10);
std1.age = 20;
strcpy(std1.name, "lele");
printf("std1--->name: %s, age: %d\n", std1.name, std1.age);
//把std1直接赋值给std2,并打印std2的值
std2 = std1;
printf("std2--->name: %s, age: %d\n", std2.name, std2.age);
//释放std1成员name所指向的内存空间
printf("std1--->name addr: %p \n", std1.name);
free(std1.name); //可以成功释放空间
//释放std2成员name所指向的内存空间
printf("std2--->name addr: %p \n", std2.name);
free(std2.name); //由于指向的空间已经释放,所以不能重复释放
return 0;
}
// std1--->name: lele, age: 20
// std2--->name: lele, age: 20
// std1--->name addr: 0x7f82b6f05b10
// std2--->name addr: 0x7f82b6f05b10
// a.out(46264,0x1108e2600) malloc: *** error for object 0x7f82b6f05b10: pointer being freed was not allocated
// a.out(46264,0x1108e2600) malloc: *** set a breakpoint in malloc_error_break to debug
// Abort trap: 6
ここでの問題は、std1 が値を std2 に代入するとき、構造内にポインターがあるため、代入は構造内のポインターが指すアドレスのみをコピーすることです。したがって、構造体 std2 を解放すると、char* がstd1 はすでにリリースされていますが、このアドレスを再度リリースしたため、リリースを繰り返すとエラーが報告されました。
ディープコピー
上記の問題に気づき、解決策の良いアイデアがあります。つまり、値を割り当てるときに構造体のメンバー変数のポインターに注意し、メモリの一部を再割り当てし、コンテンツをコピーするので、これディープコピーです。
typedef struct Student
{
char *name;
int age;
}Student;
int main(int argc, char *argv[])
{
Student std1;
Student std2;
std1.name = (char *)malloc(10);
std1.age = 20;
strcpy(std1.name, "lele");
printf("std1--->name: %s, age: %d\n", std1.name, std1.age);
//把std1直接赋值给std2,并打印std2的值
std2 = std1;
//为name成员重新分配一段空间,并把内容拷贝过来
std2.name = (char *)malloc(10);
strcpy(std2.name, std1.name);
printf("std2--->name: %s, age: %d\n", std2.name, std2.age);
//释放std1成员name所指向的内存空间
free(std1.name); //可以成功释放空间
//释放std2成员name所指向的内存空间
free(std2.name); //由于指向的不是同一段空间,可以成功释放
return 0;
}
構造体の配列
struct book {
/* set up book template */
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
int main(void)
{
struct book library[MAXBKS]; /* array of book structures */
int count = 0;
int index;
library[count].title[0];//
}
構造の入れ子
struct names {
// first structure
char first[LEN];
char last[LEN];
};
struct guy {
// second structure
struct names handle; // nested structure
char favfood[LEN];
char job[LEN];
float income;
};
int main(void)
{
struct guy fellow = {
// initialize a variable
{
"Ewen", "Villard" },
"grilled salmon",
"personality coach",
68112.00
};
printf("Dear %s, \n\n", fellow.handle.first);
}