结构体的作用
首先我们要知道结构体到底是个啥东西,struct到底是在搞什么?我们前面学过很多种类型阿,int,char,float,double,等等,这些呢都可以定义某一个东西,而被定义的那个东西就是有满足这些关键字一些特性,整型,字符型,所以我们之前学的都是只能去定义那些只有一种特性的,那么有很多东西都是集多种特点于一身的,我们来看个例子
假如说我们想要描述一个人,要把人抽象成计算机中数据.
人有哪些属性,把这些属性转换成数据,这些属性的数据都是描述人,不能把他单独分隔开.
人 : 你要关注人的哪些属性(参数)
学号 --> int num
姓名 --> char name[32]
性别--> char gender ; 'M' /'F'
年龄--> int age
地址--> char addr[32]
这个例子就很明显,因为我们不可能说先去 int person;然后又char person;这样就不对了阿,有的朋友就会说直接用你后面写的东西定义不就得了,但是注意!我们定义的是一个person,不是单独的name,单独的num,所以结构体就横空出世了,结构体就完美解决了这一问题!
结构体的定义
struct date //--> struct date 就是我定义的用来描述"日期"的类型
{ //这个类型有三个成员 : year , month ,day
int year;//年
int month;//月
int day;//日
};
上面就是一个结构体,其实非常非常好理解阿,struct就是一个操作,这个操作的目的是什么呢?就是定义一个新的类型!上面定义了一个data类型,这个data类型就和上面int,char是一样的意思,但是这个类型却又包含了多种基本类型,所以在你创建了data类型后,就要把他包含的基本型写在花括号里,花括号结束记得写分号!!!从这个分号我们其实也可以看出,虽然这个鬼结构体写那么长,其实本质上也就是struct data {};
用结构体来定义变量
struct date //--> struct date 就是我定义的用来描述"日期"的类型
{ //这个类型有三个成员 : year , month ,day
int year;//年
int month;//月
int day;//日
}day;
还是看上面这个结构体,根据结构体的定义我们知道了,data是一个新定义的类型,就和int这些一样的,那么他怎么去定义一个变量呢?之前说了,结构体就是这样的struct data {};struct data,是类型名,那么在类型名后面加一个变量名不就完成了定义了吗,当然只要你创建了这个新的类型,你后面就直接 struct data day1,这就是定义了一个data类型的day1变量!!!
struct
{ //这个类型有三个成员 : year , month ,day
int year;//年
int month;//月
int day;//日
}day;
上面struct虽然并没有写明我们创建的新类型的类型名,但是依然可以去定义一个具有多个类型的变量day,这种就有局限性,他只能在这里定义的时候去定义变量了(也就是在分号前面加上你的变量名),你在其他地方就再也不能用你这个类型去定义变量了,为什么?你这类型连个名字都没有,怎么去使用嘛,所以,一般情况下我们还是加上名字,绝对没有坏处!
结构体的地址
#include<stdio.h>
struct d
{
int b;
char c;
}h;
int main()
{
int a;
printf("%p\n",&a);
printf("%p\n",&h);
return 0;
}
/*
#include<stdio.h>
typedef struct
{
int a;
int b;
}T;
int main()
{
T t;
void *p1;
void *p2;
p1 = &t;
p2 = &t.a;
printf("p1 = %p, p2 = %p\n",p1,p2);
}
*/
结构体变量的所占内存大小,是各成员变量所占内存大小之和.
结构体变量所占的内存空间是一块连续的内存空间
各成员变量是按定义的顺序依次分配空间.
这么一看是不是特别的熟悉,这不就个数组一个样吗,确实!但是要记住阿,只有你用结构体去定义了一个变量的时候,你才能去找他的地址,不然系统是不会为他开辟空间的。有关于结构体地址的东西后面应该还会着重讲一些,后面我也会加上一位同学写的文章的连接。
结构体的的引用
#include<stdio.h>
struct data
{
int day;
int month;
int year;
};
struct person
{
char name;
struct data birth;
}p;
int main()
{
scanf("%d,%d,%d,%c",&p.birth.day,&p.birth.month,&p.birth.year,&p.name);
printf("名字:%c\n",p.name);
printf("生日:%d %d %d",p.birth.year,p.birth.month,p.birth.day);
return 0;
}
上面就是就是变量名.成员变量 ,但是其实也可以和普通变量那样,在定义的时候初始化,但是呢和普通变量不一样的地方也有,具体看下面
在定义的时候就赋值是可以的(类比:int a = 1;)
struct book s1={//对结构体初始化
"g",//author为字符数组
"yu",//title为字符串
22.5
};
下面这种就不行了,在定义变量之后,若再要对变量的成员赋值,那么只能单个赋值了;
struct book s1;
s1={
"g",
"yu",
22.5
};//这样就是不行的,只能在定义的时候初始化才能全部赋值,之后就不能再全体赋值了,只能单个赋值;(但是呢普通的类型却是可以:int a ;a = 1;)
只能;
s1.title = "yuwen";........//单个赋值;当然你也可以不按照顺序排着写,而用 .+变量名来搞定
struct student s = {
.name = {"youming"},
.birth = {
.year = 2008
}
};看见birth了吧,如果结构体里面本身又带着一个结构体,没关系你按照结构体的规则在里面展开就完事了(结构体数组先不说了)
同样的,都说了,结构体就是一个新的类型罢了,那不是说指针一样可以搞上去!
struct student s;//定义了一个结构体变量 s 类比:int a;
// 那么:int *p(很明显指针的类型应该和a相同为int型,而s的类型就算是struct student类型)
struct student *p;
p = &s;p的右值是 &s
*p ==> *&s ==> s(*p).num ==> s.num
这里还是有点疑惑留着的,就是阿你看下面
int a;
int* p = &a;
*p = 1;
这样很简单就改变了或者说赋给a值了,但是结构体呢?
struct book s;
struct book* p = &s;
这看起来好像就不那么简单了阿,因为结构体里面还有好几个东西呢,所以不能直接就赋值
可以将一个结构体变量作为一个整体赋值给另一相同类型的结构体变量,可以到达整体赋值的效果;这个成员变量的值都将全部整体赋值给另外一个变量;(2023/3/3补充)
-> 域运算符 分量运算符
这个是说明鬼呢,其实就是用来访问组合类型里面的一些变量的东东,上面不是说了吗,用指针不好去直接给赋值,那怎么办呢?那就分开一个个来嘛,->这个玩意就是用来解决这个问题的
组合类型的指针 -> 成员变量
表达式的值就最右边的那个成员变量
p->num
p->name
p->birthday.year
p->birthday.month