结构体

结构体的定义

引入

需求:想要保存学生的姓名,年龄,成绩到一个变量中,怎么办? 我们学过的数据类型中有能实现这个需求么? 数组只能保存相同数据类型的数据。

C语言提供了struct关键字 ,可以用它定义出符合条件的结构体类型。

定义

  1. 语法

struct 结构体名称 
{
     数据类型 成员变量1;
     数据类型 成员变量2;
     数据类型 成员变量3;

     ...
};

解决问题: 定义一个结构体类型来保存学生的信息。

struct Student 
{
     // 姓名
     char name[10];

     // 年龄
     int age;

     // 成绩
     int score;
};

2.初始化

int num = 10;

// 方式1
struct Student xiaoming = {"xiaoming", 18, 99}; // 结构体变量,这个变量的类型是struct Student, 变量名是 xiaoming.


// 方式2: 如果不想按照顺序初始化,就可以使用点语法
struct Student minmin = {.score = 80, .name = "minmin", .age = 20};
  1. 结构体变量的使用

如何访问结构变量的数据?

结构体变量名.成员名

比如:xiaoming.name;


// 方式1
struct Student xiaoming = {"xiaoming", 18, 99}; // 结构体变量,这个变量的类型是struct Student, 变量名是 xiaoming.

// 输出
printf("%s --- %d --- %d\n", xiaoming.name, xiaoming.age, xiaoming.score);

结构体的内存对齐规则

  • 问题思考
1)
struct A 
{
     int a;
     int b;
};

2)
struct A 
{
     int a;
     char b;
     char c;
};

3)
struct A 
{
     int a;
     char b;
     double c;
};
  • 结构体内存对齐

x86(linux 默认#pragma pack(4),window 默认#pragma pack(8))。linux 最大支持 4 字节对齐。

方法:

1.取 pack(n)的值(n= 0 2 4 8--),取结构体中类型最大值 m。两者取小即为对齐大小 k= (m<n:m,n)。

2.将每一个结构体的成员大小与 k 比较与小者,为 x;

3.所谓按 x 对齐,即为地址(设起始地址为 0)能被 x 整除的地方开始存放数据。

4.以上为结构体内部对齐,外部对齐原则是依据 x 的值作为基本单元大小进行补空操作。

对齐规则:

结构体变量中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。

补齐规则:

在经过对齐原则分析后,检查计算出的存储单元是否为所有元素中所占内存最大的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。

注意:对于结构体中有数组的,将数组作为基本数据类型来处理对齐;

结构体的指针成员

结构体的浅拷贝和深拷贝操作

1.浅拷贝 如果结构体成员有指针成员,那么结构体变量赋值之后,两个变量中的指针成员都指向同一个地址。 一旦有一个指针被释放,另外一个指针将 是野指针,不能正常访问数据。

2.深拷贝 拷贝之前先在堆空间开辟新的空间,然后将指针成员指向的数据拷贝到这块空间,这样新的结构体变量访问数据不受其他 结构体变量的影响。

int main()
{
    struct student stu1,stu2;
    stu1 = (struct student){ "张三", 30 };
    stu2 = stu1; // 结构体变量赋值
    printf("%s, %d\n", stu2.name, stu2.age);


    struct student xiaoming = { 0 }; // xiaoming的name是空指针
    struct student xiaohua = { 0 };
    xiaoming.name = calloc(20, sizeof(char));
    strcpy(xiaoming.name, "小明");
    xiaoming.age = 20;

    xiaohua.name = calloc(20, sizeof(char));
    memcpy(xiaohua.name, xiaoming.name, 20);
    xiaohua.age = 10;
    free(xiaoming.name); // 这时候即使释放拷贝之前的指针, 也不影响程序运行。
    printf("%s, %d\n", xiaohua.name, xiaohua.age);

    return 0;
}