C语言学习笔记八(结构体)

 1. 结构体基本概念

结构体是将彼此相关的,类型不同的数据组合在一起的构造数据类型,它是由若干成员组成的,每个成员的数据类型可以是基本数据类型,也可以是构造类型。在使用某个结构之前必须先声明它,即根据需要构造它。

2. 结构体声明与定义

2.1 基本声明方式

struct 结构体名 {
    数据类型 成员1;
    数据类型 成员2;
    // ...
};

示例:

struct Student {
    char name[20];
    int age;
    float score;
};

 2.2 定义结构体变量

// 方式1:先声明后定义
struct Student stu1;

// 方式2:声明时直接定义变量
struct Student {
    char name[20];
    int age;
} stu2, stu3;

// 方式3:使用typedef创建别名
typedef struct {
    char name[20];
    int age;
} Student;
Student stu4;

3. 结构体初始化

3.1 初始化方式

// 方式1:按声明顺序初始化
struct Student stu1 = {"张三", 20, 90.5};

// 方式2:指定成员初始化(C99支持)
struct Student stu2 = {
    .name = "李四",
    .age = 21,
    .score = 88.5
};

// 方式3:部分初始化
struct Student stu3 = {"王五"}; // age和score初始化为0

4. 结构体成员访问

4.1 普通变量访问

使用.运算符:

struct Student stu;
strcpy(stu.name, "赵六");
stu.age = 22;
stu.score = 95.0;

4.2 指针访问

使用->运算符:

struct Student *pStu = &stu;
pStu->age = 23; // 等价于 (*pStu).age = 23;

5. 结构体大小与内存对齐

5.1 sizeof运算符

printf("结构体大小:%zu\n", sizeof(struct Student));

5.2 内存对齐规则

  1. 结构体第一个成员的偏移量为0

  2. 每个成员按其类型大小和对齐参数的较小值对齐

  3. 结构体总大小为最大对齐参数的整数倍

  4. 可通过#pragma pack(n)修改对齐参数

示例:

struct Example {
    char a;     // 1字节
    int b;      // 通常4字节(对齐到4的倍数)
    double c;   // 8字节
};
// 在64位系统上可能占用16字节(1+3填充+4+8)

6. 结构体数组

6.1 定义与初始化

struct Student class[3] = {
    {"张三", 20, 90.5},
    {"李四", 21, 88.5},
    {"王五", 22, 92.0}
};

6.2 访问数组成员

class[1].age = 23; // 修改第二个学生的年龄

7. 结构体嵌套

7.1 嵌套结构体

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

struct Employee {
    char name[20];
    struct Date birthday;
    float salary;
};

7.2 访问嵌套成员

struct Employee emp;
emp.birthday.year = 1990;

8. 结构体与函数

8.1 结构体作为函数参数

void printStudent(struct Student stu) {
    printf("姓名:%s\n年龄:%d\n分数:%.1f\n", 
           stu.name, stu.age, stu.score);
}

8.2 结构体指针作为参数(更高效)

void modifyStudent(struct Student *pStu) {
    pStu->age += 1;
}

8.3 返回结构体

struct Student createStudent() {
    struct Student stu = {"新学生", 20, 80.0};
    return stu;
}

9. 结构体与指针

9.1 结构体指针

struct Student *pStu = malloc(sizeof(struct Student));
if (pStu != NULL) {
    strcpy(pStu->name, "动态分配");
    pStu->age = 25;
    free(pStu); // 记得释放内存
}

9.2 结构体包含指针

struct String {
    char *data;
    int length;
};

struct String str;
str.data = malloc(100);
str.length = 0;
// 使用后需要先释放data再释放String

10. 位域(Bit Fields)

允许按位分配结构体成员:

struct {
    unsigned int is_keyword : 1;  // 1位
    unsigned int is_extern  : 1;
    unsigned int is_static  : 1;
    unsigned int : 5;            // 5位未使用
    unsigned int type       : 4; // 4位
} flags;

11. 柔性数组(Flexible Array Member)

C99支持的动态大小结构体:

struct flex_array {
    int length;
    double data[]; // 柔性数组成员必须最后
};

struct flex_array *fa = malloc(sizeof(struct flex_array) + 10*sizeof(double));
fa->length = 10;

12. 结构体高级特性

12.1 匿名结构体(C11)

struct {
    int x;
    int y;
} point = {1, 2};

12.2 结构体复合字面量

printStudent((struct Student){"临时学生", 20, 85.5});

12.3 结构体比较

不能直接使用==比较,需要逐个成员比较:

int compareStudents(struct Student a, struct Student b) {
    return strcmp(a.name, b.name) == 0 &&
           a.age == b.age &&
           a.score == b.score;
}

13. 结构体常见应用场景

  1. 表示复杂数据结构(如链表、树节点)

  2. 封装相关数据(如坐标点、学生记录)

  3. 函数返回多个值

  4. 硬件寄存器映射

  5. 网络协议数据包格式

  6. 文件格式描述

14. 结构体使用注意事项

  1. 结构体赋值是值拷贝,对大型结构体可能效率低

  2. 结构体作为参数传递时,通常传递指针更高效

  3. 结构体包含指针时,需要特别注意内存管理

  4. 不同平台可能有不同的对齐方式,影响结构体大小

  5. 结构体不能包含自身类型的实例(但可以包含指针)

  6. 结构体成员默认是public的(C++中才有访问控制)

15. 结构体与联合体(Union)的区别

特性结构体(struct)联合体(union)
成员存储独立内存空间共享内存空间
总大小所有成员大小和(考虑对齐)最大成员大小
同时访问可以只能访问一个
用途组合相关数据节省内存/类型转换

16. 结构体与C++类的比较

  1. C结构体只有数据成员(C++结构体可以有函数)

  2. C结构体没有访问控制(默认public)

  3. C结构体没有继承、多态等面向对象特性

  4. C结构体更轻量级,适合底层编程

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值