C程序设计语言学习第六章 结构
第六章 结构
声明一个结构
- struct point {
int x;
int y;
}; - 关键字struct引入结构声明。结构声明由包含在花括号内的一系列声明组成。关键字struct后面的名字是可选的,称为结构标记(这里是point)。结构标记用于为结构命名,在定义之后,结构标记就代表花括号内的声明,可以用它作为该声明的简写形式。
不带变量表声明一个结构(不需要分配存储空间)
- struct point
- 结构的初始化可以在定义的后面使用初值表进行。初值表中同每个成员对应的初值必须是常量表达式,例如:
struct point maxpt = {320, 200};
访问结构中成员的方式
- 结构名.成员
- (*结构指针).成员
- 结构指针->成员
结构的合法操作
- 作为一个整体复制和赋值,通过&运算符取地址,访问其成员。其中,复制和赋值包括向函数传递参数以及从函数返回值。
- 结构之间不可以进行比较。
- 可以用一个常量成员值列表初始化结构,自动结构也可以通过赋值进行初始化。
结构数组
-
定义
- struct key {
char *word;
int count;
} keytab[NKEYS]; - 它声明了一个结构类型key,并定义了该类型的结构数组keytab,同时为其分配存储空间。数组keytab的每个元素都是一一个结构。上述声明也可以写成下列形式:
struct key {
char *word;
int count;
};
struct key keytab[NKEYS];
- struct key {
-
初始化
- struct key {
char *word;
int count;
} keytab[] = {
{ “auto”, 0 },
{ “break”, 0 },
{ “case”, 0 },
…
}; - 但是,如果初值是简单变量或字符串,并且其中的任何值都不为空,则内层的花括号可以省略。
- 如果初值存在并且方括号[ ]中没有数值,编译程序将计算数组keytab中的项数。
- struct key {
表查找
类型定义 typedef
- typedef char* String
- 以大写字母作为typedef定义的类型名的首字母以示区别
- typedef struct tnode { /* the tree node: */
char word; / points to the text /
int count; / number of occurrences */
struct tnode left; / left child */
struct tnode right; / right child */
} Treenode;
先定义了一个结构 tnode 再使用typedef tnode 定义了一个 Treenode 即 Treenode就是tnode的别名
-
这里必须强调的是,从任何意义上讲,typedef声明并没有创建一一个新类型,它只是为某个已存在的类型增加了一个新的名称而已。typedef 声明也没有增加任何新的语义:通过这种方式声明的变量与通过普通声明方式声明的变量具有完全相同的属性。实际上,typedef类似于#define语句,但由于typedef是由编译器解释的,因此它的文本替换功能要超过
预处理器的能力。 -
优势
- 使程序更简洁
- 它可以使程序参数化,以提高程序的可移植性。如果typedef声明的数据类型同机器有关,那么,当程序
移植到其它机器上时,只需改变typedef类型定义就可以了。 - 为程序提供更好的说明性一- Treeptr 类型显然比一一个声明为指向复杂结构的指针更容易让人理解。
联合
-
联合是可以(在不同时刻)保存不同类型和长度的对象的变量,编译器负贵跟踪对象的长度和对齐要求。联合提供了一种方式,以在单块存储区中管理不同类型的数据,而不需要在程序中嵌入任何同机器有关的信息。它类似于Pascal 语言中的变体记录。
-
union u_ tag {
int ival;
float fval;
char★ sval;
} u;
变量u必须足够大,以保存这3种类型中最大的一种,具体长度同具体的实现有关。这些类型中的任何一种类型的对象都可赋值给u,且可使用在随后的表达式中,但必须保证是一致的:读取的类型必须是最近一次存入的类型。程序员负贵跟踪当前保存在联合中的类型。如果保存的类型与读取的类型不一致,其结果取决于具体的实现。 -
特点
- 联合可以使用在结构和数组中,反之亦可
- 联合的所有成员相对于基地址的偏移量都是0,其大小要容得下联合中最大的成员
- 对于联合允许的操作与对结构允许的操作相同:作为一个整体单元进行赋值、复制、取地址及访问其中一个成员。
位字段 bit-field
-
定义
- 位字段简称字段,它提供了一种不需要通过按位逻辑运算符直接访问一个字中的位字段的能力
- struct {
unsigned int is_keyword : 1;
unsigned int is_extern : 1;
unsigned int is_static : 1;
} flags;
字段被声明位 unsigned int 类型以保证它们是无符号变量
-
字段的所有属性几乎都同具体的实现有关。字段是否能覆盖字边界由具体的实现定义。字段可以不命名,无名字段(只有一个冒号和宽度)起填充作用。特殊宽度0可以用来强制在下一个字边界上对齐。
-
某些机器上字段的分配是从字的左端至右端进行的,而某些机器上则相反。这意味着,尽管字段对维护内部定义的数据结构很有用,但在选择外部定义数据的情况下,必须仔细考虑哪端优先的问题。依赖于这些因素的程序是不可移植的。字段也可以仅仅声明为int,为了方便移植,需要显式声明该int类型是signed还是unsigned类型。
-
字段不是数组,并且没有地址,因此对它们不能使用&运算符。
注意
- 结构类型的参数和其他类型的参数一样,都是通过值传递的,如果传递给函数的结构很大,使用指针方式的效率通常比复制整个结构的效率要高。结构指针类似于普通变量指针。
- 但是,千万不要认为结构的长度等于各成员长度的和。因为不同的对象有不同的对齐要求,所以,结构中可能会出现未命名的“空穴“(hole)。例如,假char类型占用一个字节,int类型占用4个字节,则下列结构:
struct
{
char C;
int i;
};
可能需要8个字节的存储空间,而不是5个字节。使用sizeof运算符可以返回正确的对象长度。