一.结构体
🐓1.1什么是结构体🏀🐔
同一种类型的数据的集合是数组,和数组不同,结构体是多种类型的数据的集合。
现实生活中,我们要汇总学生的体检信息时,我们会为名字、身高、体重分别单独建表吗?显然不会。通常是给每人发一张"体检卡",在资料上面分别记录着名字、身高、体重等信息。如果一个班上有60个学生,那么50张"体检卡"即为一个集合。
下图即为"体检卡":
1.2结构体的声明
上图4个数据进行结构体的声明
- char[64]型的姓名
- int型的身高
- float型的体重
- long型的奖学金
其中,结构体的名字student称为结构名。{}中声明的name、height等称为结构体成员
注意结构体声明的末尾也要加上分号。
1.3结构体成员的类型与创建变量🚅
结构的成员可以是标量、数组、指针,甚至是其他结构体。
#include<stdio.h> //定义学生类型 struct Stu { //成员变量 char name[20]; int age; float weight; } s4, s5, s6;//全局变量 int main() { //int num = 0; //通过类型创建变量 struct Stu s1;//局部变量 struct Stu s2; struct Stu s3; return 0; }
1.4结构体成员的访问🏠
- 结构体变量访问成员
- 结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数
我们可以看到 s 有成员name和age
那我们如何访问s的成员?🍌
struct S s; strcpy(s.name, "zhangsan");//使用.访问name成员 s.age = 20;//使用.访问age成员
结构体指针访问指向变量的成员
有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针。
那该如何访问成员?⚽
struct Stu { char name[20]; int age; }; void print(struct Stu* ps) { printf("name = %s age = %d\n", (*ps).name, (*ps).age); //使用结构体指针访问指向对象的成员 printf("name = %s age = %d\n", ps->name, ps->age); } int main() { struct Stu s = {"zhangsan", 20}; print(&s);//结构体地址传参 return 0; }
两种写法同时展现:
struct Book { char name[20]; int price; }; void print(struct Book* p) { printf("%s %d\n", p->name, p->price); } int main() { struct Book b1 = {"C语言", 66}; struct Book b2 = { .price = 80, .name = "java"}; //结构体变量.结构体成员 printf("%s %d\n", b1.name, b1.price); printf("%s %d\n", b2.name, b2.price); //结构体指针->结构体成员 //struct Book* p1 = &b1; print(&b1); return 0; }
1.5结构体和typedef
typedef声明是创建数据类型的同义词的声明(而非创建新的数据类型)🐔
错误使用☀️
typedef struct { int data; Node* next; }Node;
应该先有一个完整的类型名才能使用Node,而成员变量里面已经使用了,存在先后顺序问题
正确使用☁️
typedef struct Node { int data; struct Node* next; }Node;
为简化创建变量的过程,可以讲类型名重定义,就会使用到typedef
typedef struct Book { char name[20]; int price; }Book;//不能再将全局变量加在这里后面 Book b3;//全局 Book b4;//全局 int main() { struct Book b1; struct Book b2; Book b3;//struct Book的别名 return 0; }
对类型名的重命名也可以用到
struct Book { char name[20]; int price; }; typedef struct Book Book;
不同点⚡
这里是两个不同的东西 struct { char c; int a; double d; }s1;//匿名结构体变量 typedef struct { int data; char c; } S;//结构体类型,本来是没有名字的,现在重新起名字
1.6特殊的声明
匿名结构体定义变量🐶
struct //省略了结构名 struct+结构名=类型名 { char c; int a; double d; }s1;//匿名结构体只能这样定义变量 int main() { struct s2;//错误,不能这样写 return 0; }
匿名结构体是一次性用品
匿名结构体成员相同但类型不同🐰
struct { char c; int a; double d; }s1; struct { char c; int a; double d; }* ps; int main() { ps = &s1;//err return 0; }
- 相同结构体类型:
通过同一个结构体 定义出来的变量 就相当于 int a; int b
a和b是两个不同的变量,但是它们的类型都是int类型
- 结构体类型不同: (上图就是结构体类型不一样)
用一个结构体类型的指针 指向另一个结构体类型的指针时 编译器会报出警告,类型不兼容
虽然两个匿名结构体类型的成员都完全相同,但是他们的类型还是不同的
1.7结构的自引用📍
//这是一个错误的示范 struct Node { int data; struct Node n;//自己类型的变量 };
这里是结构体中的一个成员是它这个结构体本身。 那它无限套娃 永远也停止不了
这属于线性数据结构,一个结点包括数据域和指针域
正确写法:
//当一个结构体要找到另外一个同类型的结构体的时候 //应该在自己类型里面包含一个自己类型的指针,而不是自己类型的变量 struct Node { int data;//4 struct Node* next;//4/8 }; int main() { struct Node n1; struct Node n2; n1.next = &n2; return 0; }