13.字符串,结构,联合
结构
数组可以通过下标访问,以为数组的元素长度相同。 结构通过成员名字访问,不能用下标访问。因为它的成员长度不一致。 相同类型的结构变量互相之间尅赋值。 声明结构: struct tag { member-list; } variable-list; struct { int a; char b; float c; } x; struct { int a; char b; float c; } y[20], *z; // 这是2个不同的结构类型, z = &x 错的 所以 ,tag 就派上用处了: // tag 结构标签 struct tag { int a; char b; float c; }; struct tag x; struct tag y[20],*z; z = &x; //对 另外一个技巧是用 typedef : typedef struct { int a; char b; float c; } Simple; //Simple 是个类型名而不是结构标签 Simple x; // 用类型名来声明 Simple y[20],*z; 结构成员: struct COMPLEX { float f; struct SIMPLE s; struct SIMPLE sa[10]; }; 一个结构的成员名字可以和其他结构的成员的名字相同。 结构成员的直接访问: 结构变量的成员是通过点操作符(.)访问的。 struct COMPLEX comp; comp.a 结构成员的间接访问: 拥有一个指向结构的指针,先对指针进行间接访问,获得这个结构。再使用.操作符。 要加括号,因为间接优先级没有.操作符高。 void func(struct COMPLEX *cp); (*cp).f 由于这个概念不好,C 提供了箭头操作符(->),左操作数必须是指向结构的指针, 箭头操作符对左操作数执行间接访问取得指针所指向的结构,然后和.操作符一样,根据右操作符选择一个指定的结构成员。但是间接访问操作符内建于箭头操作符内。 结构的自引用: (必须是 结构标签 + 指针) struct tag{ int a; struct tag b; }; //这种自引用是非法的,因为成员 b 是另外一个完整的结构,其内部还将包含它自己的成员b,无限重复下去。 struct tag{ int a; struct tag *b; }; // 这个是对的。b 是指针,而非结构。编译器在结构的长度确定之前就已经知道指针的长度了。 所以是合法的。如果你觉得结构内部包含一个指向结构本身的指针有些奇怪,请记住它事实上所 指向的是同一种类型的不同结构。更加高级的数据结构,如链表和树,都是用这种技巧实现的。 每个结构指向链表的下一个元素或者数的下一个分支。 //下面是错误的 typedef struct { int a; SELF_REF3 *b; int c; } SELF_REF3; 这个声明的目的是为这个结构创建类型名为 SELF_REF3.但是失败了。类型名直到声明的末尾才定义, 所以在结构声明的内部它尚未定义。 //解决方案是定义一个结构标签来声明 b typedef struct SELF_REF3_TAG{ int a; struct SELF_REF3_TAG *b; int c; } SELF_REF3; 不完整声明: struct B; struct A{ struct B *pb; }; struct B{ struct A *pa; }; 在 A 的成员列表中需要标签 B 的不完整声明。一旦A被声明之后,B的成员列表也可以别声明。 结构的初始化: struct INTT_EX { int a; short b[10]; Simple c; } x = { 10, {1,2,3,4,5}, {25,'x',1.9} }; 位段: 位段的声明和结构相似,但它的成员是一个或多个位的字段。 这些不同长度的字段实际上存储于一个或多个整形变量之中。 位段的声明和普通的结构成员声明相同,但有2个例外。首先,位段成员必须声明为 int,signed int 或者 unsigned int 类型。其次,在成员的后面是一个冒号和一个整数。 这个整数指定该位段所占用的位的数目。 struct CHAR{ unsigned ch : 7; unsigned font : 6; unsigned size : 19; }; struct CHAR ch1;联合
联合的所有成员引用的是内存中相同的位置。 union { float f; int i; } fi; 联合的初始化: // 联合变量可以被初始化,但初始值必须是联合的第一个成员的类型 union { int a; float b; char c[4]; } x = {5};