Cスタディノート - 構造 (1)

構造

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);
}

おすすめ

転載: blog.csdn.net/chongbin007/article/details/126067602