12_结构体

结构体

结构体: 将多种数据结构封装在一起 形成新的结构

每种数据结构都有自己独立的空间

结构体关键字: struct

结构体类型定义(声明)

image-20230806160756449

#include<stdio.h>
struct stu //定义结构体类型,系统不分配空间
{
    int num; //成员,不支持赋值
    char name[32];
};
int main(int argc, char const *argv[])
{
    struct stu lucy;
    struct stu alix;
    lucy.num = 10; //赋值
    alix.num = 100;
    printf("%d\n", lucy.num);
    printf("%d\n", alix.num);
    return 0;
}

结构体变量初始化

struct stu hq = {"黄齐", 23}; //结构体变量初始化
printf("%s, %d\n", hq.name, hq.age);

使用memset使结构体变量清空

struct stu mark;
memset(&mark, 0, sizeof(mark)); //memset使结构体变量清空

键盘给结构体变量赋值

struct stu ks;
scanf("%d%s", &ks.age, &ks.name);

结构体变量修改值

struct stu kj= {18, "王莹"}; //初始化
kj.age = 18;
//字符串数组 必须使用字符串操作函数进行操作
// kj.name = "王莹"; //error
strcpy(kj.name, "刘渊");
printf("%s, %d\n", kj.name, kj.age);

结构体直接赋值

struct stu xiaoming = {23, "小明"};
struct stu xiaoli = xiaoming;

内存赋值

struct stu xiaoming = {23, "小明"};
struct stu xiaoli;
memcpy(&xiaoli, &xiaoming, sizeof(xiaoming)); //string.h

结构体嵌套

struct Date
{
    int year;
    int month;
    int day;
};

struct student
{
    int num;
    char name[32];
    struct Date date;
};
int main(int argc, char const *argv[])
{
    struct student lucy = {100, "lucy", {2019, 10, 21}};
    printf("%d\n", lucy.date.year);
    return 0;
}

结构体数组

struct stu edu[5] = {{"小明", 20}, {"小丽", 23}, {"小华", 56}, 		{"小齐", 20}, {"小史", 34}};
// memset(edu, 0, sizeof(edu)); //清0
int n = sizeof(edu)/sizeof(edu[0]);
for (int i = 0; i < n; i++)
{
    printf("%s, %d\n", edu[i].name, edu[i].age);
}

结构体指针变量

struct stu lucy = {"lucy", 23};
struct stu *p = &lucy; //指针变量
printf("%s, %d\n", p->name, p->age);
printf("%s, %d\n", (*p).name, (*p).age);
printf("%s, %d\n", (&lucy)->name, (&lucy)->age);

结构体的指针成员

指针成员: 指针变量作为结构体的成员

指针成员指向文字常量区

struct stu
{
    int age;
    char *name; //指针成员
};
int main(int argc, char const *argv[])
{
    struct stu lucy = {18, "lucy"}; //"lucy" ===> 文字常量区
    printf("%c\n", lucy.name[0]); //'l'
    lucy.name[0] = 'U'; //段错误,文字常量区只读
    return 0;
}

指针成员指向堆区

struct stu lucy;
lucy.age = 18;
//让name指向堆区
lucy.name = (char *) calloc(1, 128); 
// lucy.name = "lucy"; //error 内存泄漏 name指向了文字常量区丢失了		堆区空间
strcpy(lucy.name, "lucy");
printf("%s, %d\n", lucy.name, lucy.age); //lucy, 18
lucy.name[0] = 'U';
printf("%s, %d\n", lucy.name, lucy.age); //Uucy, 18
//释放堆区空间
if (lucy.name != NULL)
{
    free(lucy.name);
    lucy.name = NULL;
}

浅拷贝

image-20230810165004028

深拷贝

如果结构体中有指针成员, 尽量使用深拷贝

struct stu bob;
bob.name = (char *) calloc(1, 128);
bob.age = lucy.age;
strcpy(bob.name, lucy.name);

image-20230810165548972

这样就不会出现问题

结构体在堆区 结构体的指针成员指向堆区

struct stu
{
    char *name;
    int age;
};
int main(int argc, char const *argv[])
{
    struct stu *p = NULL;
    p = (struct stu *)calloc(1, sizeof(struct stu));
    p->name = (char *)calloc(1, 128);
    p->age = 32;
    strcpy(p->name, "lucy");
    printf("%s, %d\n", p->name, p->age);
    if (p->name != NULL) //先释放成员变量
    {
        free(p->name);
        p->name = NULL;
    }
    if (p != NULL) //后释放结构体指针
    {
        free(p);
        p = NULL;
    }
    return 0;
}

结构指针数组

image-20230811223612502

struct stu
{
    char *name;
    int age;
};

int main(int argc, char const *argv[])
{
    struct stu **arr = NULL;
    int n = 5; // 结构数组元素个数
    arr = (struct stu **)calloc(n, sizeof(struct stu *));
    for (int i = 0; i < n; i++)
    {
        arr[i] = (struct stu *)calloc(1, sizeof(struct stu));
        arr[i]->age = 10 + i;
        arr[i]->name = (char *)calloc(1, 128);
        sprintf(arr[i]->name, "lucy%d", i);
    }
    for (int i = 0; i < n; i++)
    {
        printf("%s, %d\n", arr[i]->name, arr[i]->age);
    }
    for (int i = 0; i < n; i++)
    {
        if (arr[i]->name != NULL)
        {
            free(arr[i]->name);
            arr[i]->name = NULL;
        }
        if (arr[i] != NULL)
        {
            free(arr[i]);
            arr[i] = NULL;
        }
    }
    if (arr != NULL)
    {
        free(arr);
        arr = NULL;
    }

    return 0;
}

结构体自动类型对齐

对齐规则

image-20230817143329276

确定分配单位(一行分配多少字节)

结构体中最大的基本类型长度决定(char 1 int 4 short 2 long 8)

确定成员的偏移量

成员偏移量 = 成员自身类型的整数倍

struct Data
{
  char a; //1字节
  int b; //4字节
  short c; //2字节
}

image-20230817152033848

收尾工作

结构体的总大小 = 分配单位的整数倍

结构体嵌套结构体 自动对齐规则

确定分配单位(一行分配多少字节)

所有结构体中最大的基本类型长度决定(char 1 int 4 short 2 long 8)

确定成员的偏移量

普通成员偏移量 = 成员自身类型的整数倍

结构体成员的偏移量 = 该结构体中最大的基本类型的 整数倍

收尾工作

结构体的总大小 = 分配单位的整数倍

例子:

image-20230817180213288

image-20230817180500035

强制对齐

#pragma pack(value) 

image-20230818144653200

结构体的位域

位域(位段): 结构体中以位为单位的成员

struct Data
{
  unsigned int a: 2; //a类型是unsigned int 大小只占2位二进制位
}

image-20230818154922962

不要对位域取地址:

struct A Adata;
&Adata.a; //错误, 系统以字节为单位分配地址空间, 这里是位

对位域赋值 不用超过 位域本身位的宽度

data.a = 5; //溢出

另起一个存储单元

unsigned char : 0; //另起一个存储单元

image-20230818160651173

无意义位段

struct Data
{
    unsigned char a: 4;
    unsigned char : 2; //两位无意义位段
    unsigned char b: 2;
}data;
printf("%lu\n", sizeof(data)); //1字节

image-20230818160955980

共用体 union

结构体: 所有成员拥有独立空间

共用体: 所有成员共享一块空间

union Data
{
  char a;
  short b;
  int c;
};

成员abc共享同一块空间(最大成员空间决定)

union Data data;
data.a = 10;
data.b = 20;
data.c = 30;
printf("%d\n", data.a + data.b + data.c); //90(30+30+30)

成员共享同一块空间,但每个成员能操作的空间由成员自身类型长度决定

image-20230824165754541

image-20230824170136361

共用体将众多结构体统一, 但每个共用体空间只能存放一个数据,否则会覆盖

image-20230824171333862

枚举 enum

枚举: 将枚举变量要赋的值一一列举出来

int poker_color;
enum POKER_COLOR{HONGTAO, MEIHUA, FANGKUAI, HEITAO}; //枚举列表的值默认从0开始递增

image-20230824172217860

image-20230824172350862

posted @ 2023-08-24 17:27  爱吃冰激凌的黄某某  阅读(9)  评论(0编辑  收藏  举报