zoukankan      html  css  js  c++  java
  • 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 结构、指针和成员

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

  • 相关阅读:
    SCRUM站立会议
    燃尽图
    第一次作业----词频统计
    构建之法读感
    final 评论 II
    final 评论 I
    第十一周PSP
    学期回顾
    第十周PSP
    Gradle学习笔记
  • 原文地址:https://www.cnblogs.com/wjw-blog/p/10438282.html
Copyright © 2011-2022 走看看