3、结构体与共用体

结构体

C语言结构体(Struct)从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,是由 int、char、float 等基本类型组成的。你可以认为结构体是一种聚合类型。

在实际开发中,我们可以将一组类型不同的、但是用来描述同一件事物的变量放到结构体中。例如,在校学生有姓名、年龄、身高、成绩等属性,将它们都放到结构体中即可。

结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要内存空间来存储。

定义

struct 结构体名{
    结构体所包含的变量或数组
};

结构体变量

方式一,先定义结构体再声明结构体变量

#include<stdio.h>

struct Student{
   char *name;
   int age;
};

int main(){
   //声明结构体变量
   struct Student s1,s2;
   return 0;
}

方式二,定义结构体的同时声明结构体变量

#include<stdio.h>

struct Student{
   char *name;
   int age;
}s1,s2;

int main(){
   
   return 0;
}

结构体名也可以省略

#include<stdio.h>

struct{
   char *name;
   int age;
}s1,s2;

int main(){
   
   return 0;
}

成员获取和赋值

格式:结构体变量.成员名

#include<stdio.h>

struct Student{
   char *name;
   int age;
}s1;

int main(){
   s1.name = "Lucy";
   s1.age = 18;

   printf("姓名:%s",s1.name);
   printf("年龄:%d",s1.age);
   return 0;
}

也可以在声明变量的时候按照成员顺序整体进行赋值

#include<stdio.h>

struct Student{
   char *name;
   int age;
}s1 = {"lucy",18};

int main(){
   struct Student s2 = {"tom",22};

   printf("姓名:%s",s1.name);
   printf("年龄:%d\n",s1.age);
   printf("姓名:%s",s2.name);
   printf("年龄:%d",s2.age);
   return 0;
}

结构体数组

#include<stdio.h>

struct Student{
   char *name;
   int age;
};

int main(){
   //声明结构体数组
   struct Student stus[] = {
      {"lucy",18},
      {"tom",25},
      {"lily",16}
   };
    
   for(int i = 0;i < sizeof(stus)/sizeof(stus[0]);i++){
      printf("第%d个学生,姓名:%s,年龄:%d\n",i,stus[i].name,stus[i].age);
   }
   return 0;
}

第0个学生,姓名:lucy,年龄:18
第1个学生,姓名:tom,年龄:25
第2个学生,姓名:lily,年龄:16

结构体指针

定义格式:struct 结构体名 *变量名

#include<stdio.h>

struct Student{
   char *name;
   int age;
};

int main(){
   struct Student s1 = {"lucy",18};

   //声明结构体指针
   struct Student *p = &s1;
   printf("%#x\n",p);
   //可以通过->来访问结构体指针指向的结构体成员
   printf("姓名:%s,年龄:%d",p->name,p->age);

   //解引用
   struct Student s = *p;
   printf("姓名:%s,年龄:%d",s.name,s.age);
   return 0;
}

0x62fe00
姓名:lucy,年龄:18

共用体

共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。

共用体有时也被称为联合或者联合体,这也是 Union 这个单词的本意。

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

定义

union 共用体名{
    共用体所包含的变量或数组
};

位域

有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位。正是基于这种考虑,C语言又提供了一种叫做位域的数据结构

在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。

struct 位域结构名 {
    位域列表
    type [member_name] : width ;
};
元素 描述
type 只能为 int(整型),unsigned int(无符号整型),signed int(有符号整型) 三种类型,决定了如何解释位域的值。
member_name 位域的名称。
width 位域中位的数量。宽度必须小于或等于指定类型的位宽度。

C语言标准规定,位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,:后面的数字不能超过这个长度。

typedef

C语言允许为一个数据类型起一个新的别名,C语言允许为一个数据类型起一个新的别名,例如,有一个结构体Stu

//声明结构体变量
struct Stu s;

使用typedef可以简化

typedef struct Stu{} Stu;

//声明结构体变量
Stu