C和C指针小记(十五)-结构和联合

1、结构

1.1 结构声明

在声明结构时,必须列出它包含的所有成员.这个列表包括每个成员的类型和名称.
struct tag {member-list} variable-list;
例如

//A
struct {
    int a;
    char b;
    float c;
} x;
//B
struct {
    int a;
    char b;
    float c;
} y[20], *z;

注意:这两个声明会被编译器当作两种截然不同的类型,即使他们的成员列表完全相同.
下面这跳语句是非法的
z = &x;
可以利用tag(标签)字段来给结构的成员列表提供一个名字. 标签允许多个声明使用同一个成员列表,并创建同一种类型的结构.

//标签 SIMPLE  和这个成员列表联系在一起了. 但它没有创建任何变量. 标签不是结构的名字,更不能用来定义结构
struct SIMPLE {
    int a;
    char b;
    float c;
};
//根据标签声明结构
struct SIMPLE x;
struct SIMPLE y[20], *z;
z = &x;//x ,y ,z 都是同一种类型的结构变量

一种更好的定义结的方法:

    typedef struct {
        int a;
        char b;
        float c;
    } Simple;
    Simple x;
    Simple y[20], *z;
现在 Simple 是结构的名称了,而不是成员列表的标签.

1.2 结构成员

结构成员可以是标量,数组,指针甚至是其他结构

struct COMPLEX {
    float f;
    int a[10];
    long *lp;
    struct SIMPLE s;
    struct SIMPLE sa[10];
    struct SIMPLE *sp;
};
一个结构的成员的名字可以和其他结构的成员的名字相同,所以这个结构的成员a 并不会与 struct SIMPLE s; 的成员a冲突.

1.3 结构体成员的访问

直接访问
如果有一个结构体
struct COMPLEX comp;
可以用 . 访问结构调整的成员
comp.s
comp.s.a 或者 (comp.s).a
( (comp.sa)[4] ).c 或者 comp.sa[4].c
点操作符的结合是从左到右的
间接访问
如果拥有一个指向结构的指针,这时要访问这个结构的成员.要首先对指针执行间接反问操作.
然后使用点操作符反问它的成员. 但是点操作符的优先级是高于间接访问操作符的.所以你必须在表达式中使用括号..

void func( struct COMPLEX *cp);
(*cp).f;

由于**点操作符的优先级是高于间接访问操作符 ** 使得间接访问必须加括号,这一点体验很不好.
好在C语言提供了更为方便的箭头操作符来完成间接访问 ->
例如上例
cp->f
cp->a
cp->s
但是使用箭头操作符访问成员时,左操作数必须是一个指向结构的指针

1.4 结构的自引用

//非法
struct SELF_REF1 {
    int a;
    struct SELF_REF1 b;
    int c;
};
//合法
struct SELF_REF2 {
    int a;
    struct SELF_REF2 *b;
    int c;
};

结构自引用的形式必须是指针.编译器在结构的擦含高浓度确定之前就已经知道指针的长度,所以这种类型的自引用是合法的.
不用纠结,因为它事实上所指向的是同一种类型的不同结构. 链表和树都是用这种技巧实现的.

一个陷阱:

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;

1.5 不完整的声明

如果必须声明一些相互之间存在依赖的结构,并且每个结构都引用来其他结构的标签,那么该首先声明那些结构呢?
这个时候就用到不完整声明了.

struct B;
struct A {
    struct B *partner;
    //...
};
struct B {
    struct A *partner;
    //...
};

1.6 结构的初始化

值放在花括号内部,由都好分割初始值列表.

struct INT_EX {
    int a;
    short b[10];
    Simple c;
} x = {
    10,
    {1, 2, 3, 4, 5 },
    {25, 'x', 1.9}
};

2 结构、指针和成员

直接通过指针访问结构和它们的成员的操作符是相当简单的.

posted @ 2019-02-26 17:33  wjwdive  阅读(181)  评论(0编辑  收藏  举报