结构体类型的声明
结构体的概念
结构体是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量
举个例子:杰克的英语只考了60分,你需要将杰克考试的信息填在一张表中,那么表中的信息应该有姓名 班级 学号 分数,表就是杰克信息的集合,而姓名班级等等则都是表中成员,姓名具体对应的名称为杰克,则就称为成员变量
从上面的例子不难看出,结构体中的成员可以是不同类型的变量,我们再回想一下数组,数组的每个成员是不是都是同一种类型的变量,由于结构体和数组都是一些值的集合,因此我推断出数组是结构体的特殊情况(虽然表现的形式有区别)
结构体的声明
struct tag(tag为你自己设定的名称) { member-list;//成员列表 }variable-list;//变量列表(可有可无)
我们依然用上面的例子:
//描述杰克的英语成绩 struct Stu { char name[20];//名字 int class[20];//班级 char id[20];//学号 char Score[20];//分数 };
如果我们需要对杰克 约翰 等人填写信息的话,我们需要创建多个变量
方式一:
struct Stu { char name[20];//名字 int class[20];//班级 char id[20];//学号 char Score[20];//分数 }s1,s2,s3;//是三个结构体变量(是全局变量)
方式二:
struct Stu { char name[20];//名字 int class[20];//班级 char id[20];//学号 char Score[20];//分数 } int main() { struct stu s4,s5,s6//局部变量 return 0; }
特殊的声明
在声明结构的时候,可以不完全的声明比如:
//匿名结构体类型 struct { int a; char b; float c; }x;//只能用一次 struct { int a; char b; float c; }a[20], * p;//只能用一次
我们来看一段代码:
struct { char name[20] }a; struct { char name[20] }*p; int main() { p = &a; return 0; }
虽然两个结构体里面的变量是一样的,但是在运行时VS仍然会把他认为是两种不同的结构体,既是你将b结构体的地址传给p,也不能让p变成b的结构体
结构的自引用
在结构中包含⼀个类型为该结构本身的成员是否可以呢?
比如:
struct Node { int data; struct Node next; };
仔细分析,其实是不行的,因为一个结构体中再包含一个同类型的结构体变量,这样结构体变量的大小就会无穷的大,是不合理的
在学到这里时我其实想到了一个数学例子
虽然这个结果是可以求极限的,但是这个嵌套的方式和这道题非常类似
正确的自引用方式:
struct Node { int data; struct Node* next; }; 如果我们用的是同类型结构体指针struct Node* next,我们就可以算出内存大小了,因为*next是具体指向一个地址,有且只有一个,所以内存不会无限大
在结构体自引用使用的过程中,夹杂了typedef对匿名结构体类型重命名,也容易引入问题,看看下面的代码
typedef struct { int data; Node* next; }Node;
结果是不行的,因为Node是对前面的匿名结构体类型的重命名产生的,但是在匿名结构体内部提前使用Node类型来创建成员变量,导致结构体还没有完全创建出来就拿出来用,这很明显是不行的.
解决方案如下:定义结构体不要使用匿名结构体了
typedef struct Node { int data; struct Node* next; }Node;
这里要和上面的例子要区别开,因为在一开始我们就让结构体类型为Node,所以在中间我们可以直接拿来用
结构体变量的创建和初始化
有了结构体类型,那如何定义变量,其实很简单,结构体变量的初始化使用{}
struct Point//描述坐标的一个点 { int x; int y; }p1; //声明类型的同时定义变量p1 struct Point p2; //定义结构体变量p2 //初始化:定义变量的同时赋初值。 struct Point p3 = { x, y }; struct Stu //类型声明 { char name[15];//名字 int age; //年龄 }; struct Stu s = { "zhangsan", 20 };//初始化 struct Node { int data; struct Point p; struct Node* next; }n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化 //如果要打印struct Node中的struct Point p的话 printf("%d %d",Node.p.x,Node.p.y) struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化
指示器初始化方式(C99),这种方式允许不是按照成员顺序初始化
struct Stu { char name[15]; int age; }; struct Stu s = {.age=20, .name="zhangsan"};//初始化
.age就可以准确的将20赋值给age,这样就可以不按照成员顺序初始化了
结构成员访问操作符
结构成员访问操作符有两个一个是 . ,一个是 -> .
形式如下:
结构体变量.成员变量名 结构体指针—>成员变量名
我们看一个例子:
#include <stdio.h> #include <string.h> struct Stu { char name[15];//名字 int age; //年龄 }; void print_stu(struct Stu s) { printf("%s %d\n", s.name, s.age); } void set_stu(struct Stu* ps) { strcpy(ps->name, "李四"); ps->age = 28; } int main() { struct Stu s = { "张三", 20 }; print_stu(s); set_stu(&s); print_stu(s); return 0; }