C语言 结构体(struct)

C定义结构体

struct 结构名     
{           
	类型  变量名;           
	类型  变量名;          
	...;
} 结构变量;   

结构名是结构的标识符不是变量名。

注意: 在一般情况下,结构名、中间类型定义、结构变量 这 3 部分至少要出现 2 个;

例如:

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct
{
    int a;
    char b;
    double c;
} s1;

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE
{
    int a;
    char b;
    double c;
};
//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;

//也可以用typedef创建新类型
typedef struct
{
    int a;
    char b;
    double c;
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;

在上面的声明中,第一个和第二声明被编译器当作两个完全不同的类型,即使他们的成员列表是一样的,如果令 t3=&s1,则是非法的。

结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。

//此结构体的声明包含了其他的结构体
struct COMPLEX
{
    char string[100];
    struct SIMPLE a;
};

//此结构体的声明包含了指向自己类型的指针
struct NODE
{
    char string[100];
    struct NODE *next_node;
};

如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明,如下所示:

struct B;    //对结构体B进行不完整声明

//结构体A中包含指向结构体B的指针
struct A
{
    struct B *partner;
    //other members;
};

//结构体B中包含指向结构体A的指针,在A声明完后,B也随之进行声明
struct B
{
    struct A *partner;
    //other members;
};

C 访问结构体

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Student
{
    char name[20];
    int age;
};

int main()
{
    struct Student stu1;
    struct Student stu2;

    strcpy(stu1.name, "aaa");
    stu1.age = 10;

    strcpy(stu2.name, "bbb");
    stu2.age = 15;

    printf("stu1 name = %s, age = %d \n", stu1.name, stu1.age);
    printf("stu2 name = %s, age = %d \n", stu2.name, stu2.age);

    return 0;
}

运行结果为

stu1 name = aaa, age = 10
stu2 name = bbb, age = 15

C 结构体作为函数参数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Student
{
    char name[20];
    int age;
};


void logStudent(struct Student stu)
{
    printf("Student name = %s, age = %d \n", stu.name, stu.age);
}

int main()
{
    struct Student stu1;
    struct Student stu2;

    strcpy(stu1.name, "aaa");
    stu1.age = 10;

    strcpy(stu2.name, "bbb");
    stu2.age = 15;

    logStudent(stu1);
    logStudent(stu2);

    return 0;
}

运行结果

Student name = aaa, age = 10
Student name = bbb, age = 15

C 指向结构的指针

定义指向结构的指针,如下所示

struct Student *stu;

然后我们取变量地址,并赋值给指针

struct_pointer = &stu1;

最后我们就可以访问指针

struct_pointer->name;

示例如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Student
{
    char name[20];
    int age;
};


void logStudent(struct Student stu)
{
    printf("Student name = %s, age = %d \n", stu.name, stu.age);
}

void logStudent2(struct Student *stu)
{
    printf("Student name = %s, age = %d \n", stu->name, stu->age);
}

int main()
{
    struct Student stu1;
    struct Student stu2;

    strcpy(stu1.name, "aaa");
    stu1.age = 10;

    strcpy(stu2.name, "bbb");
    stu2.age = 15;

    logStudent2(&stu1);
    logStudent2(&stu2);

    return 0;
}

C 位域

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。

所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

典型的实例:

  • 用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。
  • 读取外部文件格式——可以读取非标准的文件格式。例如:9 位的整数。

定义语法

struct 位域结构名
{
  位域列表
};

示例

struct Article{
    int show1:8;
    int show2:2;
    int show3:6;
}a1;

说明 a1 为 Article 变量,共占两个字节。其中位域 show1 占 8 位,位域 show2 占 2 位,位域 show3 占 6 位。

C 位域的定义细节说明
  • 一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始
struct TestStruct{
    unsigned x:4;
    unsigned  :4;    /* 空域 */
    unsigned y:4;    /* 从下一单元开始存放 */
    unsigned z:4
}
  • 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长,一些编译器可能会允许域的内存重叠,另外一些编译器可能会把大于一个域的部分存储在下一个字中。
  • 位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct TestStruct{
    int a:1;
    int  :2;    /* 该 2 位不能使用 */
    int b:3;
    int c:2;
};

从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。

C 位域的使用
位域变量名.位域名
位域变量名->位域名

示例如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Test
{
    unsigned  x:1;
    unsigned  y:4;
    unsigned  z:8;
};

void logTest(struct Test *test)
{
    printf("x = %d, y = %d, z = %d \n ", test->x, test->y, test->z);
}

int main()
{
    struct Test test1;
    struct Test *test2;

    test1.x = 1;
    test1.y = 3;
    test1.z = 5;

    test2 = &test1;

    logTest(&test1);
    logTest(test2);

    return 0;
}