结构体
如何使用结构体
首先,创建一个结构体:
struct book { int math; int english; int history; };
这个结构体名字叫 book ,有3个 成员 分别是int型的数学英语历史。
注意这里的book是结构体的名字,那么如果我们要使用这个结构体,可以用它声明一个变量
比如:
struct book { int math; int english; int history; }college
这样我就用结构体book 声明了一个变量名字叫college,就类似于你用 int a = 5; 声明了一个整型常量i 这个值是5。
那如果我也想给我刚刚声明的college赋值呢
struct book { int math; int english; int history; }college = {10,20,30};
对,就类似于你用int a = 5;一样,只不过结构体用声明了一种结构体类型book,并且给里面的成员分别赋了值
当然了你也可以这样:
struct book { int math; int english; int history; }; struct book college = {10,20,30};
这两种方法没有任何区别。
结构体的成员,也可以是另一个结构体,对,可以套娃:
struct physical { char a; int b; double c; }; struct book { int math; int english; int history; struct physical num123; }college;
我在book这个结构体中加入了一个名为num123的结构体,这个结构体是physical型的。
结构体指针
如果我想用*p指向一个数组,那么很简单
int a[10] = {1,2,3,4,5,6,7,8,9,0}; int *p = a;
这个指针指向了数组a的首地址,也就是&a[0],对于数组来说,a、&a[0]都可以表示数组的首地址。那么如果我想要指向一个结构体呢?
这样吗:
int *p = book; int *p = college;
没错,显然是不对的,(因为会报错),结构体的名字并不是结构体的首地址
那么我很聪明的取了地址,这样:
int *p = &book; int *p = &college;
首先排除&book,因为book是结构体类型,就相当于你int *p = &int ,非常愚蠢。
那么&college呢?显然编译器会告诉你类型不匹配,所以我们可以通过强转的方式让其成为int
int *p = (int*)&college;
既然没有报错,就说明这种方法是可行的。
事实也确实如此,但是这样做如果你想指向里面的成员变量,就只能使用*p *(p+1) *(p+2) 这种方法访问成员,但是你能保证所有成员都是同样大小吗,
如果不能那么就要计算每个成员的大小才能准确的指向你要的地址,所以不要这么做。
数组可以通过这种方式访问,那是因为数组首先地址是连续的,并且同类型的数组每个单元占空间一定相同,所以*(p+1)一定是p的下一个值。但是结构体中不会这样。
正确的做法是
struct book *p = &college;
声明一个结构体指针p,指向college
那么如何使用该指针:
p->math = 10; p->english = 20;
也可以用这种方式:
(*p).math = 10; (*p).english = 20;
结构体传参
普通的变量可以作为参数使用,传入函数中,那么结构体也同理;
我们先来看一下一般的“正经”函数:
int add(int a,int b) { return a + b; }
printf("%d/n",add(1,2));
函数的运行结果显然等于3
那我怎么用结构体呈现同样的效果呢?
//首先我声明一个结构体 结构体名字是num 有2个成员 a和b struct num { int a; int b; }; //然后声明一个函数,使用结构体传参 int add2(struct num tmp) { return tmp.a + tmp.b; }
int main()
{ //在使用这个函数之前,要先把结构体的参数赋进去 struct num val; val.a = 1; val.b = 2; //计算并的到结果,编译运行得到3 printf("%d\n", add2(val));
return 0;
}
当然了,对于a+b这种函数肯定不需要用到结构体,这里只是举个栗子。
我们再用指针作为参数重新传一下这个函数
#include <stdio.h> //首先我声明一个结构体 结构体名字是num 有2个成员 a和b struct num { int a; int b; }; //然后声明一个函数,使用结构体传参 int add2(struct num *tmp) { return tmp->a+tmp->b; } int main() { //在使用这个函数之前,要先把结构体的参数赋进去 struct num val; struct num *p = &val; p->a = 1; p->b = 2; //计算并的到结果,编译运行得到3 printf("%d\n",add2(p)); return 0; }
typedef与结构体
typedef是用来起别名的,通常的用法是
typedef int u16
那么在后续的代码中,你就可以使用u16来替代int了,比如:
u16 a = 5; 效果等同于 int a = 5;
同样的,typedef也可以给结构体起一个新名字:
typedef struct num { int a; int b; }my_num;
相当于给num起了一个新名字叫my_num
实际上这样的声明起到了两个作用
其一:定义了一个结构体num 有两个成员a和b。
其二:给 struct num 起了一个名字叫my_num
不使用typedef的时候,当我们需要声明一个结构体变量时:
struct num tmp;
如果我用typedef给结构体起了一个小名,就可以这样声明了:
my_num tmp;