C语言——联合体/共用体

联合体和结构体类似但又不同,C语言中的联合体(Union)是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。联合体提供了一种方式,使得不同的数据类型可以共享同一段内存空间。但是,在任何给定的时刻,联合体只能存储它的成员之一的值;即联合体的所有成员从相同的内存地址开始。 

联合体的声明

联合体使用union关键字来声明,后跟联合体的名称和它的成员列表,成员列表用花括号{}括起来,成员之间用逗号,分隔。

union TestU{
	int    idata;
	char   cdata;
	double ddata;
};

在这个例子中,TestT是一个联合体,它可以存储一个int、一个char或者一个double变量。但是,在任何时候,它只能存储这三种类型之一的值。

联合体的大小

联合体的大小至少是足够存储它最大成员所需的空间。由于联合体的所有成员都从相同的内存地址开始,因此它的总大小不会是所有成员大小的总和,而是它最大成员的大小。

#include<stdio.h>

struct TestT{
	int    idata;
	char   cdata;
	double ddata;
};

union TestU{
	int    idata;
	char   cdata;
	double ddata;
};

int main()
{
	struct TestT t1;
	union  TestU u1;
	
	printf("结构体t1的大小是:%d\n",sizeof(t1));
	printf("联合体u1的大小是:%d\n",sizeof(u1));
	
	return 0;
}

输出将是:

结构体t1的大小是:16
联合体u1的大小是:8

这就体现了联合体大小计算的特点,由于联合体TestU的成员中最大的是double型变量,占据8个字节的空间,因此整个联合体的大小是8个字节。而结构体大小的计算则是其内所有成员大小的和,即为16个字节。

访问联合体的成员

你可以通过联合体变量来访问它的成员,就像访问结构体的成员一样。但是,你需要确保在访问某个成员之前,该成员是最后被设置的成员,因为联合体不会跟踪当前存储的是哪个成员的值。

也就是说在对联合体内数据进行赋值时会进行覆盖。

#include<stdio.h>

union TestU{
	int    idata;
	char   cdata;
	double ddata;
};

int main()
{
	union  TestU u1;
	
	u1.idata = 10;
	u1.cdata = 'a';
	printf("u1.idata = %d",u1.idata);
	return 0;
}

输出将是:

u1.idata = 97

从输出可以看到,我们对idata赋的值是10,而程序运行打印出来的是97也及时字符'a'对应的ASCII码的值,这体现了联合体的特点。

联合体成员的地址:

联合体内成员公用一个地址,与结构体有所不同。

#include<stdio.h>

struct TestT{
	int    idata;
	char   cdata;
	double ddata;
};

union TestU{
	int    idata;
	char   cdata;
	double ddata;
};

int main()
{
	struct TestT t1;
	union  TestU u1;
	
	printf("结构体t1.idata的地址是:%p\n",&t1.idata);
	printf("结构体t1.cdata的地址是:%p\n",&t1.cdata);
	printf("结构体t1.ddata的地址是:%p\n",&t1.ddata);

	printf("联合体u1.idata的地址是:%p\n",&u1.idata);
	printf("联合体u1.cdata的地址是:%p\n",&u1.cdata);
	printf("联合体u1.ddata的地址是:%p\n",&u1.ddata);
	return 0;
}

输出将是:

结构体t1.idata的地址是:000000000061FE10
结构体t1.cdata的地址是:000000000061FE14
结构体t1.ddata的地址是:000000000061FE18

联合体u1.idata的地址是:000000000061FE08
联合体u1.cdata的地址是:000000000061FE08
联合体u1.ddata的地址是:000000000061FE08

从输出可以看出,联合体内的成员公用的是一个地址,因此才会出现赋值会被覆盖的情况。

使用情景:

有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。要求用同一个表格来处理。

分析:人员的数据基本相同,主要是要区别出学生和老师的身份,根据身份的不同,统计的信息略有区别,因此可以考虑在结构体中设置一个联合体,将这些不同的信息放进联合体中,根据身份信息的不同,来赋给联合体中不同成员的不同值,这样可以节省内存空间。

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

struct Person{
	char name[32];
	char sex[12];
	int  tele;
	char zhiye;
	union{
		int  class;
		char subject[32];
	}occup;
};

int main()
{
	struct Person p[2];
	int i;
	for(i=0;i<2;i++){
		printf("请输入职业:t代表老师,s代表学生\n");
		scanf("%s",&(p[i].zhiye));
		if(p[i].zhiye == 't'){
			printf("请输入老师的姓名:\n");
			scanf("%s",p[i].name);
			printf("请输入老师的科目:\n");
			scanf("%s",p[i].occup.subject);
		}else if(p[i].zhiye == 's'){
			printf("请输入学生的姓名:\n");
			scanf("%s",p[i].name);
			printf("请输入学生的班级:\n");
			scanf("%d",&(p[i].occup.class));
		}else{
			printf("输入错误!!\n");
			exit(1);
		}
	}
	
	for(i=0;i<2;i++){
		if(p[i].zhiye == 't'){
			printf("%s老师教的科目是%s\n",p[i].name,p[i].occup.subject);
		}else{
			printf("%s学生的班级是%d\n",p[i].name,p[i].occup.class);
		}
	}
	
	return 0;
}

这里涉及到了一些scanf相关的问题,在上面的代码中可以看到使用了多个scanf函数,其中有的使用了取地址符号&,有的没使用,其依据是:当你需要读取基本数据类型(如 int, char, float 等)的值时,你需要提供这些变量的地址,这时使用 &。但是,当你读取数组或结构体的成员时,因为它们本身就是地址,所以不需要 &。对于联合体,如果成员是基本数据类型,就需要使用 &;如果成员是数组类型,就不需要 &。因为zhiye变量和class变量是char和int基本型变量,因此使用了取地址符&。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hardStudy_h

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值