【C语言】结构体
【C语言】结构体

一、什么是结构体
C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
结构体中的数据成员可以是基本数据类型(如 int、float、char 等),也可以是其他结构体类型、指针类型等。
结构用于表示一条记录,假设您想要跟踪图书馆中书本的动态,您可能需要跟踪每本书的下列属性:
- Title
- Author
- Subject
- Book ID
二、结构体的定义
结构体定义由关键字 struct 和结构体名组成,结构体名可以根据需要自行定义。
struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:
// 结构体的一般定义形式为:
struct 结构体名{
类型名1 成员名1;
类型名2 成员名2;
······
类型名n 成员名n;
}
struct 是关键字,是结构类型的标志。
// 举个例子
struct Student
{
char *name; // 姓名
int age; // 年龄
float height; // 身高
};
上面定义了一个叫做 Student 的结构体,共有 name、age、height 3个成员。看到这里是否有点面向对象的味道呢?其实这跟面向对象完全是两码事,只能说感觉有点像。
三、结构体变量的定义
前面只是定义了名字为 Student 的结构体,并非定义了一个结构体变量,就像 int 一样,只是一种类型。
接下来定义一个结构体变量,方式有好多种。
1、先定义结构体类型,再定义变量
struct Student
{
char *name;
int age;
}; // 结构体最后有个分号别忘了
struct Student stu; // 定义了一个结构体变量,变量名为stu。struct和Student是连着使用的
2、定义结构体类型的同时定义变量
struct Student
{
char *name;
int age;
} stu; // 结构体的变量名为stu
3、直接定义结构体类型变量,省略类型名
struct
{
char *name;
int age;
} stu; // 结构体的变量名为stu
四、结构体的注意点
1、不允许对结构体本身递归定义
如下列做法是 错误 的:
struct Student
{
int age;
struct Student stu;
};
PS:结构体最后的分号一定不要忘了
2、结构体内可以包含别的结构体
struct Date
{
int year;
int month;
int day;
};
struct Student
{
char *name;
struct Date birthday; // 可以包含别的结构体
};
3、定义结构体类型,只是说明了该类型的组成情况,并没有给它分配存储空间,就像系统不为 int 类型本身分配空间一样。只有当定义属于结构体类型的变量时,系统才会分配存储空间给该变量
// 新学一招, markdown 笔记使用 (``` + c) 可以直接创建 c 类型的代码块
struct Student
{
char *name; // 姓名
int age; // 年龄
};
// 截止到这里,系统并没有给结构体分配空间
struct Student stu;
// 截止到这里,系统给结构体分配了空间
4、结构体变量占用的内存空间是其成员所占内存之和,而且各成员在内存中按定义的顺序依次排列
比如下面的 Student 结构体:
struct Student
{
char *name; // 姓名
int age; // 年龄
float height; // 身高
};
在16位环境下,一个 Student 变量共占用内存:2 + 2 + 4 = 8字节。
在32位环境下,一个 Student 变量共占用内存:4 + 4 + 4 = 12字节。
在64位环境中,一个 Student 变量共占用内存:8 + 4 + 4 = 16字节

五、结构体的初始量
将各成员的初值,按顺序地放在一对大括号 { } 中,并用逗号分隔,一一对应赋值。
比如初始化 Student 结构体变量 stu
struct Student
{
char *name;
int age;
};
struct Student stu = {"MJ", 27};
只能在定义变量的同时进行初始赋值,初始化赋值和变量的定义不能分开,下面的做法是 错误 的:
struct Student stu;
stu = {"MJ", 27};
六、结构体的使用
1、一般对结构体变量的操作是以成员为单位进行的,引用的一般形式为: 结构体变量名.成员名
struct Student
{
char *name;
int age;
};
struct Student stu;
// 访问 stu 的 age 成员
stu.age = 27;
最后1行 对结构体的age成员进行了赋值。"."称为成员运算符,它在所有运算符中优先级最高
2、如果某个成员也是结构体变量,可以连续使用成员运算符 “ . ” 访问最低一级成员
struct Sate
{
int year;
int month;
int day;
};
struct Student
{
char *name;
struct Date birthday;
};
struct Student stu;
// 注意下面代码
stu.birthday.year = 2001;
stu.birthday.month = 2;
stu.birthday.day = 10;
3、相同类型的结构体变量之间可以进行整体赋值
struct Student
{
char *name;
int age;
};
struct Student stu1 = {"MJ", 27};
// 将 stu1 直接赋值给 stu2
struct Student stu2 = stu1;
printf("age is %d", stu2.age);
输出结果为:

七、结构体数组
1、定义
跟结构体变量一样,结构体数组也有3种定义方式
struct Student
{
char *name;
int age;
}
struct Student stu[5]; // 定义1
struct Student
{
char *name;
int age;
}stu[5]; // 定义2
struct
{
char *name;
int age;
}stu[5]; // 定义3
上面3种方式,都是定义了一个变量名为 stu 的结构体数组,数组元素个数是5
2初始化
struct
{
char *name;
int age;
}stu = {{"MJ", 27},{"WW", 24}};
也可以用数组下标访问每一个结构体元素,跟普通数组的用法一样
八、结构体作为函数参数
将结构体变量作为函数参数进行传递时,其实传递的是全部成员的值,也就是将实参中的成员的值一一赋值给对应的形参成员。因此,变量的改变不会影响实参。
#include <stdio.h>
// 定义一个结构体
struct Student
{
int age;
};
// 声明函数
void test(struct Student stu)
{
printf("修改前的形参:%d \n",stu.age);
// 修改实参中的age
stu.age = 10;
printf("修改后的形参:%d \n",stu.age);
}
int main()
{
struct Student stu = {30};
printf("修改前的实参:%d \n",stu.age);
// 调用 test函数
test(stu);
printf("修改后的实参:%d \n",stu.age);
return 0;
}
输出结果为:

形参是改变了,但是实参一直没有变过
九、指向结构体的指针
* 每个结构体变量都有自己的存储空间和地址,因此指针也可以指向结构体变量
* 结构体指针变量的定义形式:struct 结构体名称 *指针变量名
* 有了指向结构体的指针,那么就有3种访问结构体成员的方式
- 结构体变量名.成员名
- (*指针变量名).成员名
- 指针变量名->成员名
#include <stdio.h>
int main()
{
// 定义一个结构体
struct Student
{
char *name;
int age;
};
// 定义一个结构体变量
struct Student stu = {"MJ", 27};
// 定义一个指向结构体的指针变量
struct Student *p;
// 指向结构体变量 stu
p = &stu;
/*
这时候可以使用3种方式访问结构体的成员
*/
// 方式1:结构体变量名.成员名
printf("name = %s,age = %d \n",stu.name,stu.age);
// 方式2:(*指针变量).成员名
printf("name = %s,age = %d \n",(*p).name,(*p).age);
// 方式3:指针变量 -> 成员名
printf("name = %s,age = %d \n",p -> name,p -> age);
return 0;
}
输出结果:


浙公网安备 33010602011771号