文章目录
结构体和共用体
1.基本介绍
-1,需求:
张老太养了两只猫猫:一只名字叫做小白,今年3岁,白色。还有一只叫小花,今年100岁,花色,请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示张老太没有这只猫猫
解决方案:
传统技术解决:
1)单独定义变量解决
void main(){
char cat1Name[10]="小白";
int cat1Age=3;
char cat1Color="白色";
}
2)我们学习了数组,他是一组具有相同类型的数据的集合。在编程中,我们往往还需要一组类型不同的数据,例如猫的名字使用字符串、年龄是int,因为数据类型不同,不能使用一个数组来存放。
void main(){
char *catsName[]={
"小白",
"小花",
}
}
int catsAge[]={3,100};
传统方案的问题:
不利于数据的管理和维护,因为本身猫的三个属性(名字,年龄,颜色)是一个整体,传统解决方法是将其分解。
新技术====>>结构体
2.走向结构体
-1.结构体关系图
进一步阐述:
-2,面向对象的方式(struct)解决养猫的问题
#include <stdio.h>
//养猫问题使用结构体解决
/*
* 分析:
* 1。猫有三个成员变量组成
* 2,使用结构体
*/
//创建结构体 Cat
void main(){
//创建结构体 Cat
struct 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("\n第一只猫name=%s age=%d color=%s",cat1.name,cat1.age,cat1.color);
printf("\n第二只猫name=%s age=%d color=%s",cat2.name,cat2.age,cat2.color);
/*运行结果:
第一只猫name=小白 age=3 color=白色
第二只猫name=小花 age=100 color=花色
Process finished with exit code 37
*/
}
-3.结构体和结构体变量的区别与联系
通过上面的案例我们可以看出:
1)结构体是自定义的数据类型,表示的是一种数据类型
2)结构体变量代表一个具体变量好比
int num1; int 是数据类型,而num1是一个具体的变量
struct Cat cat1; //Cat 是结构体数据类型,而cat1是一个Cat变量
3)Cat就像一个模板,定义出来的结构体变量都含有相同的成员。也可以将结构体比作"图纸",将结构体变量比作“零件”。根据同一张图纸生产出来的零件的特性都是一样的。
-4,结构体在内存中的布局
struct Cat cat1;
cat1.name="小白";
cat1.age=3;
cat1.color="白色";
在内存中的布局
-5.结构体的声明
struct 结构体名称{//结构体名首字母大写,比如 Cat,Person
成员列表;
}
例子:
struct Student{
char *name;//姓名
int num;//学号
int age;//年龄
char group;//所在学习小组
float score;//成绩
//成员也可以是结构体
}
-6.成员
(1)基本介绍
1)从叫法上看:有些书称为成员,有些书说,结构体包含的变量
2)成员是结构体的一个组成部分,一般是一些基本数据类型;也可以是数组、指针、结构体等。比如我们前面定义Cat结构中的int age就是一个成员。
(2)注意事项与细节说明:
-
成员声明语法同变量,实例:数据类型 成员名
-
字段的类型可以为:基本类型、数组或指针、结构体等
-
在创建一个结构体变量后,需要给成员赋值,如果没有赋值就使用可能导致程序异常终止
#include <stdio.h> void main(){ struct Cat{ char *name;//名字 int age;//年龄 char *color;//颜色 }; struct Cat cat3;//定义了一个结构体变量cat1; cat3.name; cat3.age; cat3.color; printf("\n-猫name=%s age=%d color=%s",cat3.name,cat3.age,cat3.color); }
-
不同结构体变量的成员是否独立,互不影响。,一个结构体变量的成员更改,不影响另一个。
#include <stdio.h>
void main(){
struct Cat{
char *name;//名字
int age;//年龄
char *color;//颜色
};
struct Cat cat3;//定义了一个结构体变量cat1;
cat3.name="小白";
cat3.age=3;
cat3.color="白色";
printf("\n-猫name=%s age=%d color=%s",cat3.name,cat3.age,cat3.color);
}
-7.创建结构体和结构体变量
1)方式1-先定义结构体,然后再创建结构体变量
struct Stu{
char *name;//姓名
int num;//学号
int age;//年龄
char group;//所在学习小组
float score;//成绩
};//要加;
struct Stu stu1,stu2;
//定义了两个变量stru1和sru2,他们都是Stu类型,都由5个成员组成
//注意关键字struct不能少
2)方式2-在定义结构体的同时定义结构体变量
struct Stu{
char *name;//姓名
int num;//学号
int age;//年龄
char group;//所在学习小组
float score;//成绩
}stu1,stu2;
//在定义结构Stu的同时,创建了两个结构体变量stu1和stu2;
3)方式3-如果只需要stu1,stu2两个变量,后面不需要在使用结构体名定义其他变量,在定义时也可以不给出结构体名
struct {//没有写Stu
char *name;//姓名
int num;//学号
int age;//年龄
char group;//所在学习小组
float score;//成绩
}stu1,stu2;
stu1.name="tom";
stu1.num=100;....
//1.该结构体数据类型,没有名,匿名结构体
//2.stu1和stu2就是该结构体的两个变量
-8.成员的获取与赋值
结构体与数组类似,也是一组数据的集合,整体使用没有太大意义。数组使用下标[]获取单个元素,结构体使用点号.获取单个成员。获取结构体成员的一般格式为结构体变量名.成员名
1)案例1:
struct {//没有写Stu
char *name;//姓名
int num;//学号
int age;//年龄
char group;//所在学习小组
float score;//成绩
}stu1;
stu1.name="jack";
printf("%s",stu1.name)
2)案例2
#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};
printf("\nstu1.name=%s",stu1.name);
struct Student stu3={"林黛玉2",12,16,'A',100};
printf("\nstu3.name=%s",stu3.name);
struct Student stu4;
//stu4={"林黛玉2",12,16,'A',100};//erro,这样不可以,除非单个赋值
stu4.name="smith";
printf("\nstu4.name=%s",stu4.name);
}
3.结构体应用实例
-1.步骤
1)声明(定义)结构体,确定结构体名
2)编写结构体的成员
3)白那些处理结构的函数
-2.小狗案例
1)编写一个额Dog结构体,包含name(char[10])、age(int)、weight(double)属性
2)编写一个say函数、返回字符串,方法返回信息中包含所有成员值
3)在main方法中,创建Dog结构体变量,调用say函数,将调用结果打印输出。
#include <stdio.h>
//定义一个结构体
struct Dog{
char *names;
int age;
double weight;
};
//say函数,返回字符串,信息包含所有成员值
char *say(struct Dog dog){
//将这个信息放入一个字符串当中
static char info[50];
sprintf(info,"name=%s age=%d weight=%.2f",dog.names,dog.age,dog.weight);
dog.names="小花";//这里改动对输出没有任何影响,因为是值传递
return info;
}
void main(){
//测试
//定义结构体变量
struct Dog dog;
char *info=NULL;
dog.names="小黄";
dog.age=1;
dog.weight=3.4;
info=say(dog);//结构体默认是值传递
printf("\n小狗信息为:%s",info);
}
-3.盒子案例
1)创建一个Box结构体,在其中定义三个成员表示一个立方体的长、宽
和高,长宽高可以通过控制台输入
2)定义一个函数获取立方体的体积(volume)
3)创建一个结构体,打印给定尺寸的立方体体积。
#include <stdio.h>
struct Box{
double len;
double width;
double height;
double volumn;//体积
};
double out(){
struct Box box;
printf("请输入长宽高:");
fflush(stdout);
scanf("%lf%lf%lf",&box.len,&box.width,&box.height);
getchar();
box.volumn=box.len * box.width * box.height;
return box.volumn;
}
void main(){
printf("该长方体的体积是:%.2f",out());
}
//运行结果是:
请输入长宽高:3 3 3
该长方体的体积是:27.00
Process finished with exit code 23
-4.景区门票案例
1)一个景区根据游人的年龄收取不同价格的门票
2)请编写游人结构体(Vistor),根据年龄段决定能够购买的门票价格并输出
3)规则:年龄>18,门票为20元,其他情况,免费
4)可以循环从控制台输入名字和年龄,打印门票收费情况,如果名字输入n则退出程序
#include <stdio.h>
#include <string.h>
/*
* 1)一个景区根据游人的年龄收取不同价格的门票
2)请编写游人结构体(Vistor),根据年龄段决定能够购买的门票价格并输出
3)规则:年龄>18,门票为20元,其他情况,免费
4)可以循环从控制台输入名字和年龄,打印门票收费情况,如果名字输入n则退出程序
*/
struct Vistor{
char name[10];
int age;
double pay;//应付票价
};
//编写函数处理业务逻辑
//说明:因为结构体默认是值传递,会拷贝一份完整的数据,效率较低
//因此为了提高效率我们直接接收一个指针
void ticket(struct Vistor *vistor){
//判断
if((*vistor).age>18){
(*vistor).pay=20;
}else{
(*vistor).pay=0;
}
}
void main(){
//测试
//创建结构体变量(创建一个游客)
struct Vistor vistor;
//死循环一直循环下去
while(1){
printf("\n请输入游客名字:");
fflush(stdout);
scanf("%s",vistor.name);
if(strcmp("n",vistor.name)==0){
break;
}
printf("\n请输入游客年龄:");
fflush(stdout);
scanf("%d",&vistor.age);
//调用函数ticket,获取应付的票价
ticket(&vistor);//取地址放进去
printf("\n该游客应付票价=%.2f",vistor.pay);
}
printf("退出程序!!");
}
//运行结果:
请输入游客名字:张得
请输入游客年龄:12
该游客应付票价=0.00
请输入游客名字:jabs
请输入游客年龄:34
该游客应付票价=20.00
请输入游客名字:n
退出程序!!
Process finished with exit code 12
4.共用体
-1.基本介绍
需求
现有一个关于学生信息和教师信息的表格。学生信息包括姓名、编号、性别、职业、分数、教师的信息包括姓名、编号、性别、职业、教学科目。请看下面表格
Name | Num | Sex | Profession | Score/Course |
---|---|---|---|---|
孙二娘 | 501 | 女(f) | 学生(s) | 89.5 |
吴用 | 1011 | 男(m) | 老师(t) | math |
顾大嫂 | 109 | 女(f) | 老师(t) | English |
林冲 | 982 | 男(m) | 学生(s) | 95.0 |
解决方案:
1)传统方案:
定义结构体,根据人员的职业,使用对应的成员变量。
struct Person{
char name[20];
int num;
char sex;
char proffession;
float score;//学生使用score
char course[20];//老师使用course
};
传统方式的问题分析:会造成空间的浪费,比如学生只使用score,但是也占用了course成员的20个字节
解决方案:
1)做struct Stu 和struct Teacher【但如果职业很多,就会对应多个结构类型,不利于管理】
2)使用共用体
-2.走向共用体
1)介绍
-
共用体(Union)属于构造类型,它可以包含多个类型不同的成员。和结构体非常类似,但是也有不同的地方
-
共用体有时也被称为联合或者联合体,定义格式为
union 共用体{ 成员列表 };
-
结构体和共用体的区别在于:结构体的各个成员会占用不同的内容,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
2)快速入门
定义共用体类型和共用体变量的三种方式(和结构体一样)
第一种:
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;
案例;
#include <stdio.h>
union data{//一个公共体数据类型,包含3个成员共享数空间,该空间的大小以占用最大的成员为主
int n;//4bytes
char ch;//1bytes
short m;//2bytes
};
void main(){
union data a;//定义一个共用体变量
printf("%d,%d\n",sizeof (a),sizeof(union data));//4,4(以类型最大的为主)
a.n=0x40;//4*16=64
printf("%d,%c,%d\n",a.n,a.ch,a.m);//后面两个变量也有值64,@(64的ASCII),64
a.ch='9';//字符9对应的十进制是57
printf("%d,%c,%d\n",a.n,a.ch,a.m);//57,9,57
a.m=0x2059;//8281
printf("%d,%c,%d\n",a.n,a.ch,a.m);//8281,Y,8281(char一个字节发现是89对应的Ascii是Y0)
a.n=0x3E25AD54;//1042656596
printf("%d,%c,%d\n",a.n,a.ch,a.m);//1042656596,T,-21164
}
data内存布局:
-3最佳实践:
使用共用编程对以上表格进行编程
#include <stdio.h>
#define TOTAL 1 //人员总数
//定义了一个结构体
union MYUNION{
float score;
char course[20];
};
struct Person{
char name[20];
int num;//编号
char sex;//性别 f==>女 m=>男
char profession;//职员 s==>学生 t==>老师
union {
float score;
char course[20];
}sc;//sc是一个共用体变量~
//union MYUNION sc;
};
void main(){
int i;
struct Person persons[TOTAL];//定义一个共用体变量数组
//录入人员信息
for(i=0;i<TOTAL;i++){
printf("Input info;");
fflush(stdout);
scanf("%s %d %c %c",persons[i].name,&(persons[i].num),&(persons[i].sex),&(persons[i].profession));
if(persons[i].profession=='s'){//如果是学生
printf("请输入该学生的成绩:");
fflush(stdout);
scanf("%f",&persons[i].sc.score);
}else{//是老师
printf("请输入该老师所教的课程:");
fflush(stdout);
scanf("%s",&persons[i].sc.course);
}
fflush(stdin);//刷新输入
}
//输出人员信息
printf("\nName\tNum\tSex\tProfession\tScroce/Course\n");
for(i=0;i<TOTAL;i++){
if(persons[i].profession=='s') {//如果是学生
printf("%s\t\t%d\t%c\t%c\t\t\t%.2f\n",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%c\t\t\t%s\n",persons[i].name,persons[i].num,persons[i].sex,persons[i].profession,persons[i].sc.course);
}
}
}
//运行结果
Input info;小伟 14 f s
请输入该学生的成绩:78
Name Num Sex Profession Scroce/Course
小伟 14 f s 78.00
Process finished with exit code 21