> 文档中心 > 【掌握结构体类型的定义、结构体变量的初始化、赋值与成员访问】(学习笔记13--结构体)

【掌握结构体类型的定义、结构体变量的初始化、赋值与成员访问】(学习笔记13--结构体)

目录

  • 👉 结构
    • 🌈结构体类型的定义
    • 🌈结构体变量的定义
      • 1️⃣先定义结构体类型,再定义结构体变量
      • 2️⃣在定义结构体类型的同时定义结构体变量
      • 3️⃣定义无名结构体类型变量
    • 🌈结构体变量的初始化与赋值
    • 🌈结构体成员的访问
    • 🌈结构体的大小
    • 🌈结构体的嵌套

前言

变量可以用来存储单个数据数组可以用来存储一组同类型的数据,但它们都只适合单一属性的数据。结构体属于复合数据类型,结构体可以拥有众多的成员,而且各成员的数据类型可以各不相同,因此它非常适合拥有多属性的对象进行存储

👉 结构体

🌈结构体类型的定义

结构体类型的定义格式:
首先是struct关键字,然后是结构体类型的名字,后面紧跟着一对大括号,在大括号中定义该结构体的各个成员,每个成员的定义方式与变量类似,由数据类型和成员名组成,最后,在大括号的后面要有一个分号,以表示结构体定义的结束

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

由于每个成员的数据类型可以各不相同,因此非常适合多属性的对象。

struct Person{char name[20];//姓名int age;//年龄float height;//身高float weight;//体重};

上面定义出的是一个结构体类型,它是不能用于存储数据的。就好像int是一个数据类型,它是不能用于存储数据的,如果想要存储一个int类型的数据,就需要再定义出该类型的变量

int a;

定义一个int类型的变量a,它可用来存储一个int类型的数据
同理,如果想要存储某个人的数据,就得根据结构体类型person再定义出该类型的变量

🌈结构体变量的定义

定义结构体变量的方式有3种

1️⃣先定义结构体类型,再定义结构体变量

这种方式是最普遍的,和定义基本数据类型的变量一样,根据定义好的结构体类型来定义出该类型的结构体变量

struct Person p1;

结构体类型不光是类型名字本身,前面还需要加上struct关键字

2️⃣在定义结构体类型的同时定义结构体变量

定义结构体类型Person时,在大括号与分号之间,直接定义出了该结构体类型的变量p2

struct Person{char name[20];int age;float height;float weight;}p2;

3️⃣定义无名结构体类型变量

这种方式与第2种方式有些类似,也是在定义结构体类型时定义结构体变量,但并没有指定类型名

struct{char name[20];int age;float height;float weight;}p3;

定义一个局部的结构体变量时,就需要选择第1种方式;
快捷地定义出全局的结构体变量时,就可以选择第2种方式;
不想在定义结构体类型之外的地方进行结构体变量定义时,就应该选择第3种方式

在定义结构体变量时,也可以同时定义多个,只需在变量名之间用逗号分隔即可

struct Person p4,p5;
struct Person{char name[20];int age;float height;float weight;}p7,p8;
struct{char name[20];int age;float height;float weight;}p9,p10;

🌈结构体变量的初始化与赋值

定义结构体变量时,可以对其进行初始化。结构体变量的初始化方式与数组类似,不同的是,列表中初始值的类型和顺序要与结构体成员的类型和顺序匹配

struct Person p1 = {"Tom",20,1.78f,63.5f};

初始化的时候,只给出部分初始值,没有对应的初始值,编译器会将其值初始化为0

struct Person p2 = {"Jack",22};

对于结构体类型与结构体变量在同时定义的情况下,也可以对结构体变量进行初始化

struct Person{char name[20];int age;float height;float weight;}p3 = {"Hill",23,1.80f,75.5f};

❗❗❗数组间是不能相互赋值的,结构体变量间却可以相互赋值

将结构体变量p1赋值给结构体变量p2后,结构体变量p2各成员的值会与p1各成员的值相同

p2 = p1;

也可以将一个结构体变量,作为一个结构体变量的初始值,经过初始化后,结构体变量p4各成员的值与p1各成员的值相同

struct Person p4 = p1;

需要注意的是,不论是赋值还是初始化,两边的结构体变量的类型都必须一致

struct A a1 = p1;//错误

p1是struct Person类型的结构体变量,而a1被定义为struct A类型的结构体变量,因此,不能将p1作为a1的初始值。即便两个结构体变量所拥有的成员类型、数量和顺序完全相同,也不可以。对于赋值,也是同样的道理

🌈结构体成员的访问

使用成员访问运算符来访问结构体变量的各成员,成员访问运算符用英文的点字符“.”来表示。也有人将其形象地称为点运算符,功能就是通过成员访问运算符来访问结构体变量名所表示的结构体变量的指定成员

结构体变量名.成员名
p1.name

通过成员访问运算符来访问结构体变量p1的name成员。下面通过printf函数name成员打印输出

printf("Name: %s\n",p1.name);

结果

Name: Tom

也可以对name成员重新赋值

strcpy(p1.name,"David");printf("Name: %s \n",p1.name);

由于name成员的类型是长度为20的字符数组,而数组是不能直接对其进行赋值的。因此,我们利用string.h头文件中的strcpy函数,将一个字符串复制到指定的字符数组中

Name: David

可见,name成员所存储的字符串,已从原来的Tom,修改成了David

在对结构体变量进行初始化时,也可以使用成员访问运算符,即对结构体变量进行指定初始化的方式

struct Person p5 = {.name = "Rose",.height = 1.65f};
printf("Name: %s\n",p5.name);printf("Age: %d\n",p5.age);printf("Height: %.2f m\n",p5.height);printf("Weight: %.2f kg\n",p5.weight);

没有初始化的成员就会被编译器初始化为0

Name: RoseAge: 0Height: 1.65 mWeight: 0.00 kg

也可以在结构体变量p5的初始化之后,再为它的另外两个成员进行赋值

p5.age = 25;p5.weight = 50.5f;

再使用printf函数来打印p5所有成员

Name: RoseAge: 25Height: 1.65 mWeight: 50.50 kg

🌈结构体的大小

基本数据类型具有相对固定的大小,而结构体是复合数据类型,它的成员的类型、数量是不固定的,那么一个结构体的大小是多少呢?

可以通过sizeof运算符来获取结构体的大小,即结构体类型或该类型的结构体变量的大小

printf("Size of the struct Person: %u bytes.\n",sizeof(struct Person));printf("Size of the p1: %u bytes.\n",sizeof p1);

Person结构体共有4个成员,第一个成员是长度为20的字符数组,大小为20字节;第二个成员为int类型,大小为4字节;第三和第四个成员都为float类型,大小都是4字节。将4个成员的大小合计在一起,共32字节,这就是Person结构体的大小

Size of the struct Person: 32 bytes.Size of the p1: 32 bytes.

结构体的大小也许会大于成员大小的总和

struct A{char a;//1字节int b;//4字节char c;//1字节}
printf("Size of the struct A: %u bytes.\n",sizeof(struct A));
Size of the struct A: 12 bytes.

结构体A的大小为12字节,并非6字节,这是为什么呢?
因为编译器对结构体成员进行了内存对齐的处理,目的是为了访问结构体成员。
将整个结构体的大小设置为4的倍数,并以4字节为一个单位对成员进行存储,如果单位内的剩余空间大于成员的大小,就将成员存入该单位,否则就将成员存放于下一单位的内存。如果一个单位存放不下成员,就用多个单位来进行存储

结构体Person和结构体A的成员存储情况如下图
在这里插入图片描述
由图可见,结构体A的第一个成员a只占用了第一个单位4字节中的第一个字节,第三个成员c只占用了第三个单位4字节中的第一个字节

下面,在定义结构体A时,将成员b和成员c的位置互换一下

struct A{char a;//1字节char c;//1字节int b;//4字节}

重新打印输出结构体A的大小,结果如下

Size of the struct A: 8 bytes.

可见,结构体在定义时,成员位置的不同,会造成结构体大小的不同,这是因为编译器对结构体成员进行内存对齐的原因

结构体A的大小变为8字节。其中成员a和成员c都会存储在第一个单位的4字节内,而成员b则单独占用了第二个单位的4字节,如下图
在这里插入图片描述

🌈结构体的嵌套

可以将一个结构体作为另一个结构体的成员,即允许结构体的嵌套使用

先定义一个关于日期的结构体类型Date

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

然后,在Person结构体中再添加一个Date结构体类型的成员birthday,用来表示人的生日。

struct Person{char name[20];int age;float height;float weight;struct Date birthday;//生日}

定义一个struct Person类型的结构体变量zs,并对其进行初始化

struct Person zs = {"ZhangSan",20,1.82,78.5,1999,8,28};

也可以将birthday的这三个成员的初始值再使用大括号括起来,就会更清晰了

struct Person zs = {"ZhangSan",20,1.82,78.5,{1999,8,28}};

zs前面四个成员都是基本数据类型,通过一个成员访问符,就可以访问到它们

zs.name;zs.age;zs.height;zs.weight;

而zs的第五个成员是一个struct Date类型的结构体变量birthday,所以,我们需要两个成员访问运算符才能访问到birthday的成员

zs.birthday.year;zs.birthday.month;zs.birthday.day;

在这里插入图片描述