C语言之复合类型

322 阅读2分钟

结构体

在C语言中,结构体其实就是一种自定义数据结构,类似Java中的类。使用关键字struct创建。

  • 定义
struct Student {
    char name[21];
    unsigned int age;
    char tel[16];
    float scores[3];
    char sex;
};
  • 声明
int main() {
    // 创建变量方式一
    struct Student student = {"Lucy", 18, "13912345678", 89.0f, 69.0f, 77.0f, 'F'};
    // 二
    struct Student student1 = {
            .name = "Lucy",
            .age = 18,
            .tel = "13912345678",
            .scores[0] = 89.0f,
            .scores[1] = 69.0f,
            .scores[2] = 77.0f,
            .sex = 'F'
    };
    // 三
    struct Student student2;
    // 不能直接这样赋值
//    student2.name = "Lucy";
    strcpy(student2.name, "Lucy");
    student2.age = 18;
    strcpy(student2.tel, "13912345678");
    student2.scores[0] = 89.0f;
    student2.scores[1] = 69.0f;
    student2.scores[2] = 77.0f;
    student2.sex = 'F';
    printf("%s\n", student.name);
    return EXIT_SUCCESS;
}
  • 结构体大小

结构体大小等于其所有成员变量所占内存大小之和。

struct Person1 {
    char arr[2];    // 2
    char *p;        // 8
    short d;        // 2
    int c;          // 4
    // long类型在windows上是占4个字节,Mac上是8个字节
    long g;         // 8
    double f;       // 8
    float h[2];     // 8

} person1;

struct Person2 {
    char *p;        // 8
    double f;       // 8
    float h[2];     // 8
    // long类型在windows上是占4个字节,Mac上是8个字节
    long g;         // 8
    int c;          // 4
    char arr[2];    // 2
    short d;        // 2

} person2;

int main() {
    printf("%zd\n", sizeof(person1));	// 48
    printf("%zd\n", sizeof(person2));	// 40
    return EXIT_SUCCESS;
}

为什么Person1Person2所占的内存大小不一样?因为结构体是根据数据类型进行内存对齐的。如下图

原因是结构体需要根据数据类型进行内存对齐,并且是大端对齐。

所以,定义结构体成员变量时,把大的数据类型写在上面。

  • 结构体指针与结构体嵌套
struct Class {
    char *className;    // 8
    char sex;           // 4
} clz;

struct Person3 {
    char *name;         // 8
    unsigned int age;   // 4
    struct Class class;

} person3;

int main() {
    printf("%zd\n", sizeof(person3));       // 32
    struct Person3 *p = malloc(sizeof(person3));
    p->name = malloc(sizeof(char) * 6);
    strcpy(p->name, "Hello");
    p->age = 18;
    p->class.className = malloc(sizeof(clz));
    strcpy(p->class.className, "三班");
    p->class.sex = 'F';
    printf("%s\t%d\t%s\t%s\n", p->name, p->age, p->class.className, p->class.sex == 'F' ? "男" : "女");
    if (p->class.className) {
        free(p->class.className);
    }
    if (p->name) {
        free(p->name);
    }
    if (p) {
        free(p);
    }
    return EXIT_SUCCESS;
}

共用体

共用体是一个能在同一个存储空间存储不同类型数据的类型,但每一瞬时只有一种起作用;共用体变量的地址和它的各成员的地址都是同一地址,所以,在存入一个新的成员后,原有的成员的值会被覆盖。

union Bean {
    double a;
    float b;
    int c;
    short d;
    char e;

} bean;

int main() {
    // 共用体所占的内存长度等于其最长成员的长度
    printf("%zd\n", sizeof(bean));// 8
    bean.a = 10;
    bean.c = 2;
    // 在共用体中最后一次赋值,它的值为准确的
    bean.e = 'C';
    printf("%.f\n", bean.a);    // 10
    printf("%d\n", bean.c);     // 67
    printf("%c\n", bean.e);     // C
    return EXIT_SUCCESS;
}

枚举

enum Color {
    // 默认从0开始
    red, blue, yellow
} color;

int main() {
    switch (color) {
        case red:
            printf("%d\n", red);
            break;
        case blue:
            printf("%d\n", red);
            break;
        case yellow:
            printf("%d\n", red);
            break;
    }
    return EXIT_SUCCESS;
}

typedef

// 给struct Student3起别名stu3
typedef struct Student3 stu3;


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

int main() {
    // 使用时就可以直接使用别名了
    stu3 stu = {.name = "Tom", .age = 18};
    return EXIT_SUCCESS;
}