C 연구 노트 - 구조(1)

구조

C는 구조와 배열이라는 두 가지 집계 데이터 유형을 제공합니다.
배열에 저장된 각 요소는 동일한 유형이지만 구조체는 다른 유형을 저장할 수 있습니다.구조체의 각 요소는 구성원이라고 하며 각 구성원 유형은 다를 수 있습니다.

배열 이름과 달리 구조 변수는 표현식에서 사용될 때 포인터로 대체되지 않으며 구조 변수는 멤버를 선택하기 위해 첨자를 사용할 수 없습니다.

변수 선언 및 생성

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;

자기 참조 구조

다음 자체 참조는 멤버 s가 내부에 자체 멤버 s를 포함하는 또 다른 완전한 구조이고 두 번째는 완전한 구조이기 때문에 불법입니다. 이 구조의 크기를 계산할 때 무한히 반복되는 재귀 크기를 계산할 수 없으므로 불법입니다.

struct Simple {
    
         
	int a;
	struct Simple s;
	flaot b;
};

다음 명령문은 명령문이 포인터이고 길이를 직접 계산할 수 있기 때문에 적법합니다.

struct Simple {
    
         
	int a;
	struct Simple *p;
	flaot b;
};

자체 참조 트랩

typedef를 사용하여 구조를 선언할 때

typedef struct {
    
         
	int a;
	Simple *p;
	flaot b;
} Simple;

그러나 선언이 끝날 때까지 유형 이름이 정의되지 않고 구조가 선언될 때 정의되지 않기 때문에 실패합니다.
해결책 중 하나는 태그를 생략하지 않는 것입니다.

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