C语言中Union与struct知识汇总

结构体struct

   今天在看程序时,对Union的应用比较陌生,特此对union 和struct进行梳理和分析,以后就能快速应用啊,希望今天的整理,能帮到同样对此有困惑的你。

定义结构体的三种方式

#include<stdio.h>
//定义结构体的三种方式
struct A{ //方式一
int a;
long *b;
char c[20];
};

struct{ //方式二
int a;
long *b;
char c[20];
}s1;

typedef struct B{ //方式三
int a;
long *b;
char c[20];
}Byt;

int main(){

struct A age; 
age.a=4;//初始化方式一

s1.a=6; //初始化方式二

Byt s2;
s2.a=7;//初始化方式三 

/*--------------------------------------------------------------------------------------------------------------------------

结构体大小计算

结构体默认的字节对齐一般满足三个准则:

  1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
  2. 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
  3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)

结构体的自引用

struct B{
int a;

     struct B b;

     int c;

};

    这种引用是不合法的,因为b是一个完整的结构,第二个成员又是另一个完整的结构,还包括她自己的成员,这样会循环下去无法及所结构体的大小。

struct B{
int a;

     struct B  *b;

     int c;

};

这种声明是合法的,b现在是一个指针它所占的字节数是已知的,可以计算出结构体的大小,这种自引用是合法的。

结构体数组与结构体指针

(1)结构体数组
一个结构体可以用来存储一组信息,但是对于多组信息,我们就需要用数组在来处理。此时,每一个结构体数组的元素,就是一个结构体变量。
#include<stdio.h>

//申请记录学生信息的结构体
struct student{
char name[6];
int age;
char Idcard[18];
};

int main(){

struct student stu[10];

int i=0;

for(i=0;i<10;i++){
	
	stu[i].age=10+i;
	
	printf("%d\n",stu[i].age);	
}

return 0; 

}
(2)结构体指针
一个结构体变量的指针就是该结构体变量所占据内存段的起始地址。因此可以设一个指针变量指向结构体变量,此时该指针变量的值是结构体变量的起始地址。同时指针变量也可以用来指向结构体数组中的元素。借用C语言中文网上的例程如下:
#include <stdio.h>
#include <string.h>
struct AGE
{
int year;
int month;
int day;
};
struct STUDENT
{
char name[20]; //姓名
int num; //学号
struct AGE birthday; //生日
float score; //分数
};
int main(void)
{
struct STUDENT student1; /用struct STUDENT结构体类型定义结构体变量student1/
struct STUDENT *p = NULL; /定义一个指向struct STUDENT结构体类型的指针变量p/
p = &student1; /p指向结构体变量student1的首地址, 即第一个成员的地址/
strcpy((*p).name, “小明”); //(*p).name等价于student1.name
(*p).birthday.year = 1989;
(*p).birthday.month = 3;
(*p).birthday.day = 29;
(*p).num = 1207041;
(*p).score = 100;
printf(“name : %s\n”, (*p).name); //(*p).name不能写成p
printf(“birthday : %d-%d-%d\n”, (*p).birthday.year, (*p).birthday.month, (*p).birthday.day);
printf(“num : %d\n”, (*p).num);
printf(“score : %.1f\n”, (*p).score);
return 0;
}

联合体Union

   联合体与结构体之间的区别是:结构体的各个成员会占用不同的内存,相互之间无影响。而联合体的所有成员公用一段内存,修改一个成员会影响其余所有成员。结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),联合体占用的内存等于最长的成员占用的内存。联合体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

联合体的定义

   第一种方式是先定义联合体,在创建变量:

union data{
int n;
char ch;
double f;
};
union data a, b, c;
第二种方式是在定义联合体时创建变量:
union data{
int n;
char ch;
double f;
} a, b, c;
第三种是如果不再定义新的变量,也可以将共用体的名字省略:
union{
int n;
char ch;
double f;
} a, b, c;

联合体应用

 在此借用C语言中文网上的例程来讲解Union的特点:

#include<stdio.h>

union data{
int n;
char ch;
short m;
};

int main(){

union data a;
printf("%d, %d\n", sizeof(a), sizeof(union data) );

a.n = 0x40;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.ch = '9';
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.m = 0x2059;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.n = 0x3E25AD54;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);

return 0;

}
运行结果如下:
4, 4
40, @, 40
39, 9, 39
2059, Y, 2059
3E25AD54, T, AD54

  通过运行结果我们可以看出,Union中首地址固定,各成员变量公用一段内存,在同一时刻,联合体的变量按自身内存大小公用这段内存。因此,Union可以解决结构体中部分成员共用一段内存的问题,进行Union和struct之间的相互嵌套。下面再应用一个案例来说明,详细网址:http://c.biancheng.net/view/2035.html
  共用体在一般的编程中应用较少,在单片机中应用较多。对于 PC 机,经常使用到的一个实例是: 现有一张关于学生信息和教师信息的表格。学生信息包括姓名、编号、性别、职业、分数,教师的信息包括姓名、编号、性别、职业、教学科目。请看下面的表格:

在这里插入图片描述
f 和 m 分别表示女性和男性,s 表示学生,t 表示教师。可以看出,学生和教师所包含的数据是不同的。现在要求把这些信息放在同一个表格中,并设计程序输入人员信息然后输出。

  如果把每个人的信息都看作一个结构体变量的话,那么教师和学生的前 4 个成员变量是一样的,第 5 个成员变量可能是 score 或者 course。当第 4 个成员变量的值是 s 的时候,第 5 个成员变量就是 score;当第 4 个成员变量的值是 t 的时候,第 5 个成员变量就是 course。

   经过上面的分析,我们可以设计一个包含共用体的结构体,请看下面的代码:

#include <stdio.h>
#include <stdlib.h>
#define TOTAL 4 //人员总数
struct{
char name[20];
int num;
char sex;
char profession;
union{
float score;
char course[20];
} sc;
} bodys[TOTAL];
int main(){
int i;
//输入人员信息
for(i=0; i<TOTAL; i++){
printf(“Input info: “);
scanf(”%s %d %c %c”, bodys[i].name, &(bodys[i].num), &(bodys[i].sex), &(bodys[i].profession));
if(bodys[i].profession == ‘s’){ //如果是学生
scanf("%f", &bodys[i].sc.score);
}else{ //如果是老师
scanf("%s", bodys[i].sc.course);
}
fflush(stdin);
}
//输出人员信息
printf("\nName\t\tNum\tSex\tProfession\tScore / Course\n");
for(i=0; i<TOTAL; i++){
if(bodys[i].profession == ‘s’){ //如果是学生
printf("%s\t%d\t%c\t%c\t\t%f\n", bodys[i].name, bodys[i].num, bodys[i].sex, bodys[i].profession, bodys[i].sc.score);
}else{ //如果是老师
printf("%s\t%d\t%c\t%c\t\t%s\n", bodys[i].name, bodys[i].num, bodys[i].sex, bodys[i].profession, bodys[i].sc.course);
}
}
return 0;
}
运行结果:
Input info: HanXiaoXiao 501 f s 89.5↙
Input info: YanWeiMin 1011 m t math↙
Input info: LiuZhenTao 109 f t English↙
Input info: ZhaoFeiYan 982 m s 95.0↙

Name Num Sex Profession Score / Course
HanXiaoXiao 501 f s 89.500000
YanWeiMin 1011 m t math
LiuZhenTao 109 f t English
ZhaoFeiYan 982 m s 95.000000

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值