结构体和共用体
结构体和共用体
1.结构体
1.1 看一个养猫问题
张老太养了两只猫猫:一只叫小白,今年3岁,白色,还有一只叫小花,今年100岁,花色,请编写一个程序,当用户输入小猫的名字,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示张老太没有这只猫猫
1.2 使用传统技术解决
- 单独的定义变量解决
- 学习完数组,它是一组具有相同类型的数据的集合,在编程中,我们往往还需要一组类型不同的数据,例如猫的名字使用字符串,年龄是int,因为数据类型不同,不能用一个数组来存放
1.3 现有技术解决的缺点分析
- 不利于数据的管理和维护,因为本身猫的三个属性(名字,年龄,颜色)是一个整体,传统解决方法是将其分解-->结构体
```c
void main(){
char cat1Name[10]="小白";
int cat1Age=3;
char cat1Color[10]="白色";
char *catsName[2]={
"小白"
"小花"
};
int catsAge[2]{3,100}
}
1.4 结构体与结构体变量的关系示意图
把所有猫的特征提取出来---->cat结构体-数据类型(成员 name age color)
说明:除了可以有cat结构体,还可以有person结构体,有fish结构体等
1.5 快速入门--面向对象的方式解决养猫问题
#include<stdio.h>
void main(){
//分析:
//1.猫猫有三个成员变量组成
//2.使用结构体解决
//创建结构体cat
struct Cat{//结构体名Cat,Cat就是我们自己构造的一个数据类型
char *name;//名字,使用指针,指向一个字符串
int age;
char *color;
};
//使用Cat结构体创建变量
struct Cat cat1;//cat1就是struct Cat的一个变量
struct Cat cat2;//cat2就是struct Cat的一个变量
//给cat1的各个成员赋值
cat1.name="小白";
cat1.age=3;
cat1.color="白色";
//给cat2的各个成员赋值
cat2.name="小花";
cat2.age=100;
cat2.color="花色";
//输出两只猫的信息
printf("第一只猫name=%s age=%d color=%s",cat1.name,cat1.age,cat1.color);
printf("第二只猫name=%s age=%d color=%s",cat2.name,cat2.age,cat2.color);
getchar();
}
1.6 结构体和结构体变量的区别和联系
- 结构体是自定义数据类型,表示的是一种数据类型
- 结构体变量代表一个具体变量
int num1;//int 是数据类型,而num1是一个具体的int变量
struct Cat cat1;//Cat是结构体数据类型,而cat1是一个Cat变量
- Cat就像一个”模板“,定义出来的结构体变量都含有相同的成员,也可以将结构体比作图纸,将结构体变量比作零件,根据同一张图纸生产出来的零件的特征都是一样的
1.8 如何声明结构体
struct 结构体名称{//结构体名称首字母大写,比如Cat,Person
成员列表;
};
struct Student{
char *name;
int num;
int age;
char group;
float score;
//成员也可以是结构体
};
1.9 成员
-
基本介绍
- 从叫法上看,有些书上称为成员,有些书说结构体包含的变量
- 成员是结构体的一个组成部分,一般是基本数据类型,也可以是数组,指针,结构体等;比如定义的Cat结构体的int age就是一个成员;
-
注意事项即细节说明
- 成员声明语法同变量,实例,数据类型,成员名
- 字段的类型可以为:基本类型,数组或指针,结构体等
-
在创建结构体变量后,需要给成员赋值,如果没有赋值就使用可能导致程序异常终止
#include <stdio.h>
void main(){
struct Cat(){//结构体名字建议打字大写
char *name;
int age;
char *color;
};
struct Cat cat1;//定义了一个结构体变量cat1
printf("名字=%s 年龄=%d 颜色=%s",cat1.name,cat1.age,cat1.color);
getchar();
}
- 不同结构体变量的成员是独立,互不影响,一个结构体变量的成员更改,不影响另一个
1.10 创建结构体和结构体变量
- 方式一:先定义结构体,然后再创建结构体变量
struct Stu{
char *name;
int num;
int age;
char group;
float score;
};
struct Stu stu1,stu2;
//定义了两个变量stu1和stu2,他们都是Stu类型,都由5个成员组成
//注意关键字struct不能少
- 方式二:在定义结构体的同时定义结构体变量
struct Stu{
char *name;
int num;
int age;
char group;
float score;
}stu1,stu2;
//在定义结构体Stu的同时,创建了两个结构体变量stu1和stu2
- 方式三:如果只需要stu1,stu2两个变量,后面不需要再使用结构体数据类型,定义其他变量,在定义时也可以不给出结构体名
struct {
char *name;
int num;
int age;
char group;
float score;
}stu1,stu2;
stu1.name="tom";
stu1.num=100;
//该结构体数据类型,没有名,匿名结构体
//stu1和stu2就是该结构体的两个变量
1.11 成员的获取和赋值
结构体和数组类似,也是一组数据的集合,整体使用没有太大的意义,数组使用下标[]获取单个元素,结构体使用点号。获取结构体成员的一般格式为
结构体变量名.成员名;
struct {
char *name;
int num;
int age;
char group;
float score;
}stu1;
stu1.name="jack";
printf("%s",stu.name);
#include<stdio.h>
void main(){
struct Student{
char *name;
int num;
int age;
char group;
float score;
}stu1={"贾宝玉",11,18,'B',90.50},stu2={"林黛玉",12,16,'A',100};
struct Student stu3={
"林黛玉2",12,16,'A',100
};//在定义结构体变量时,整体赋值,需要对应
struct Student stu4;
//stu4={"林黛玉2",12,16,'A',100};//这样赋值不可以
//stu4.name="smith";
printf("stu1.name=%s",stu1.name);
printf("stu3.name=%s",stu3.name);
getcahr();
}
2.结构体应用实例
2.1 步骤
- 声明结构体,确定结构体名
- 编写结构体的成员
- 编写处理结构体的函数
2.2 案例
//编写一个Dog结构体,包含name(char[10]),age(int),weight(double)属性
//编写一个say函数,返回字符串,信息中包含所有成员值
//在main方法中,创建Dog结构体变量,调用say函数,将调用结果打印输出
#include<stdio.h>
struct Dog{
char *name;
int age;
double weight;
};
//say 函数,返回字符串,信息中包含所有成员值
char *say(struct Dog dog){
//将这个信息放入到一个字符串(字符数组)
static char info[50];
sprintf(info,"name=%s age=%d weight=%.2f",dog.name,dog.age,dog.weight);
dog.name="小花";
return info;
}
void main(){
//测试
//定义结构体变量
struct Dog dog;
char *info=NULL;
dog.name="小黄";
dog.age=1;
dog.weight=3.4;
info=say(dog);//结构体变量默认是值传递
printf("小狗信息=%s",info);
printf("main 小狗信息=%s",dog.name);
getchar();
}
2.4 景区门票案例
- 一个景区根据游人的年龄收取不同价格的门票
- 请根据游人结构体(Visitor),根据年龄段决定能够购买的门票价格并输出
- 规则:年龄>18,门票为20元,其他情况免费
- 可以循环从控制台输入名字和年龄,打印门票收费情况,如果名字输入n,则退出程序
#include<stdio.h>
#include<string.h>
//定义结构体
struct Visitor{
char name[10];
int age;
double pay;//应付票价
};
//编写函数处理业务
//说明:因为结构体默认是值传递,会拷贝一份完整数据,效率较低
//因此,为了提高效率,我们直接接收地址
void ticket(struct Visitor* visitor){
//判断
if((*vistor).age>18){
(*visitor).pay=20;
}else{
(*visitor).pay=0;
}
}
void main(){
//测试
//创建结构体变量(创建一个游客)
struct Vistor vistor;
//循环输入名字和年龄
while(1){
printf("请输入名字:");
scanf("%s",visitor.name);
//判断如果名字输入n,则退出程序
if(!strcmp("n",visitor.name)){
break;
}
printf("请输入游客年龄");
scanf("%d",&visitor.age);
//调用函数ticket,获取应付的票价
ticket(&visitor);
printf("游客应付票价为%.2f",visitor.pay);
}
printf("退出程序");
getchar();
getchar();
}
3.共用体

|
3.2 传统方式解决
定义结构体,根据人员的职业,使用对应的成员变量
struct Person{
char name[20];
int num;
char sex;
char profession;
float score;//学生使用score
char cousre[20];//老师使用course
};
传统方式的问题分析:会造成空间的浪费,比如学生只使用score,但是也占用了course成员的20个字节。
- 解决方案
- 做struct Stu和struct Teacher[但如果职业过多,就会对应多个结构体类型,不利于管理]
- 使用共用体
3.3 基本介绍
-
共用体(Union)属于构造类型,它可以包含多个类型不同的成员,和结构体非常类似,但是也有不同的地方,共用体有时也被称为联合或者联合体,定义格式为
union 共用体名{
成员列表;
};
-
结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员
3.4 快速入门
- 定义共用体类型和共用体变量的三种方式(和结构体一样)
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;
union data{
int n;
char ch;
short m;
};
void main(){
union data a;
pritf("%d,%d",sizeof(a),sizeof(union data));
a.n=0x40;
printf("%d,%c,%d",a.n,a.ch,a.m);
a.ch='9';
printf("%d,%c,%d",a.n,a.ch,a.m);
a.n=0x3E25AD54;
printf("%d,%c,%d",a.n,a.ch.a.m);
}
- 案例演示
#include<stdio.h>
union data{
//data就是一个共用体(内存布局),包含三个成员,共享数据空间,该空间的大小以占用最大的成员为准
int n;
char ch;
short m;
};
void main(){
union data a;
//定义一个共用体变量a
printf("%d,%d",sizeof(a),sizeof(union data));
a.n=0x40;
printf("%d,%c,%d",a.n,a.ch,a.m);
a.ch='9';
printf("%d,%c,%d",a.n,a.ch,a.m);
a.m=0x2059;
printf("%d,%c,%d",a.n,a.ch,a.m);
a.n=0x3E25AD54;
printf("%d,%c,%d",a.n,a.ch,a.m);
getchar();
}
3.5 内存布局
3.6 内存布局分析
要深入理解为什么前面的案例输出的结果,就需要剖析共用体在内存中是如和布局的
- 成员n,ch,m,在内存中"对齐"到一头,对ch赋值修改的是前一个字节,对m赋值修改的是前两个字节,对n赋值修改的是全部字节。也就是说,ch,m会影响到n的一部分数据,而n会影响到ch,m的全部数据
- 上图是在绝大多数PC机上的内存分布情况,如果是51单片机,情况就会有所不同
3.7 最佳实践
#include<stdio.h>
#define TOTAL 2//人员总数
//定义了一个结构体Person
union MYUNION{
float score;
char score;
char course[30];
};
struct Person{
char name[20];
int num;
char sex;
char profession;
union{
float score;
char course[20];
}sc;//sc是一个共用体变量
};
void main(){
int i;
struct Person person[TOTAL];//定义了一个结构体数组
//输入人员信息
for(i=0;i<TOTAL;i++){
printf("input info:");
scanf("%s %d %c %c",person[i].name,&(person[i].name),&(person[i].num),&(person[i].sex),&(person[i].profession));
if(person[i].profession=='s'){
printf("请输入该学生成绩:");
scanf("%f",&person[i].sc.score);
}else{
printf("请输入该老师课程:");
scanf("%s",person[i].sc.course);
}
fflush(stdin);
}
//输入人员信息
printf("Name\t\tNum\tSex\tProfession\tScore\tCourse\n");
for(i=0;i<TOTAL;i++){
if(person[i].profession=='s'){
printf("%s\t\t%d\t%c\t%c\t%c\t\t%f",persons[i].name,persons[i].num,persons[i].sex,persons[i],profession,persons[i].sc.score);
}else{
printf("%s\t\t%d\t%c\t\t%s",persons[i].name,persons[i].num,persons[i].sex,persons[i].profession,persons[i].sc.course);
}
}
getchar();
getchar();
}

浙公网安备 33010602011771号