Struct.
有时候我们希望把归属于一类的信息放在一起,便于查看.如一个员工的姓名、编号、工资、出勤。它又 字符串、int、float、数组等
构成.C提供了struct,使他们聚合在一起,便于我们访问.
结构定义
很显然,结构也是一个变量,它有自己的变量名,类型是struct;除此之外,我们还要说明 它由什么构成.
(1) struct { member list } x;
这个跟 int x一样,声明一个int型变量x.此处,声明一个 由member_list 组合构成的struct 变量 x
这就有一个问题,如果我们要声明许多个变量, struct { member list } y; struct { member list } z; 这样书写下去很是繁琐.
(2) struct tag { member list } ;
为由member_list 组合构成的struct 类型,创建一个标签--tag. 相当于 struct tag是一类数据,它们由 { member list }构成.
后续可以直接使用 struct tag x ;定义一个变量x
(3) typedef struct tag { member list } TAG ;
借用typedef , 定义 TAG = struct tag . 便有了更加简洁的写法 TAG x ;
(1)(2)是更加接近底层的定义解释,(3) 只是借用typedef的简便写法,但比较实用。
结构成员的访问
typedef struct ptx { int a; char b[5]; char *p; } PTX ;
struct变量名.成员
指向struct的指针 ->成员
结构的存储
struct的存储遵循以下几个原则:
(1) 起始地址要跟 member_list里面最严格的对其。
(2) 按照顺序,依次每个member_list 都按照自己的对齐方式. 跳过非对齐位置。
(3) 末尾要补充,以保证和最严格的member_list对齐.
上图是整个struct的存储结构. 可以看出这种定义方式,对存储单元造成很大的浪费. 如果按照double、int、char[9]、char
这个顺序声明,就能节省不少存储空间.
结构 指针 和成员
typedef struct { int a ; short b[2] ; } Ex2 ; typedef struct EX { int a ; char b[3]; Ex2 c; struct Ex *d; }
首先定义了一个结构Ex2类型,它由一个int和一个长度为2 的 short 数组组成。
另一个结构EX : 它由一个int 、char[3] 、一个Ex2类型变量、一个指向EX类型的指针变量,组合而成。
如果大致的花下草图, EX结构应该是这样的存在.
如果对其进行初始化 EX my_stru = { 10, "HI", { 5 , { -1 ,25} } , 0 }
同时声明一个指向 my_stru的指针 EX *px = &my_stru ;
Px |
右值,就是p的内容--- my_stru的首地址。 左值就是存入p 对p来说,p就是一个指针变量, 只不过稍微特殊一些,指向的是一个结构体 |
*Px |
右值,获得是整个结构, 顾(*p)后面可以跟 . 操作如 *Px.a(.优先级很高的) 左值,修改整个结构。 |
*Px+1 |
*Px优先,获得一个结构整体,对其+1是不对的,因为1是int型。 |
*(Px+1) |
非法,因为不知道要表达什么内容 |
Px->a |
因为Px是一个指针,故指针和->配合 |
Int *pi Pi=&Px->a |
定义一个指针。同时把 结构的成员a的地址,赋给pi 则pi是指向 结构成员a的指针。 注意 -> . 这俩的优先级很好。 |
Px->b |
是一个数组名。 |
Px->b[1] |
是数组b的第1个元素 |
Px->c |
得到一结构名。对px->可以使用.操作,如px->c.a 将访问 小结构体内的成员a |
*px->c.b |
首先根据优先级 px->c.b得到小结构体内一个数组名。然后对 *数组名 = *(数组名+0) = 数组名[0] 即第一个元素。 充当左值,就是修改第一个元素 充当右值,就是获取第一个元素值 |
Px->d |
得到指针变量d. 我们可以使用*px->d获得 指针d指向的东西 但因为初始化,d=0,即NULL。 我们可以声明 EX y; d =&y; 即d指向结构y 那么*px->d,将得到一个结构名y. 后续可以跟 . Px->d, 得到的是 一个结构的指针。 能继续跟 -> Px->d->a Px->d->b Px->d->c.b[1] 结构如下图 |