结构体、共用体、枚举和typedef
数组:同类型的数据;
结构体:不同类型的数据;
结构体和结构体变量的关系类似与:类型与普通变量的关系,结构体中说明了结构体变量的信息格式,而结构体变量是结构体的实例;
(1)结构体定义:
只有先完成结构体的定义,才能声明并使用结构体变量,其定义是为了说明结构体变量要存储什么信息的过程。
形式:
struct 结构名称 //也称为结构标识
{
存储数据列表; //也称为成员变量列表
}; //分号不能忘记
例子:
struct person
{
char name[20];
intage;
charemail[50];
};
其中,定义了一个结构person,将name、age和email这3个数据打包;
Person 可以向int、double型变量一样,利用person声明该类型的机构变量,每个person型结构体变量都包括name、age和email这3个数据成员。
(2)声明结构体变量:
用以上person结构为例,此为一种类型,可以用来声明结构体变量zangsan:
Struct person zangsan;
区别:person只是结构体定义,是种规范说明,不分配内存空间,而zangsan是实在的结构体变量,占据内存空间;
如:
Struct person
{
Char name[20];
Int age;
Char email[50];
} zangsan, lisi,wangwu, *zaoliu;
在定义person同时,声明了3个结构体变量:zangsan、lisi、wangwu,以及声明了指向person结构的指针zaoliu。
(3)初始化结构变量:
如:
Struct person
{
Char name[20];
Int age;
Char email[50];
} zangsan={“zangsan”,24,“899586515@163.com”},*pzs=&zangsan;
完成了:a.结构体person的定义;b.声明了结构体变量zangsan,和一个指向person结构的指针pzs;c.初始化了zangsan,并用结构体变量zangsan的地址为pzs赋值。
(4)访问结构体成员:
字符串name、int型变量age和字符串email称为结构体person及其声明变量的“数据成员”,简称“成员”。
声明结构体变量后,可使用成员操作符“.”来访问各个成员:
例子:
#include<stdio.h>
#include<conio.h>
struct person
{
charname[20];
intage;
charemail[50];
};
void main(void)
{
structperson zangsan={"zang san",24,"46846@163.com"};
structperson *pzs=&zangsan;
printf("name:%s\n",zangsan.name); //name:zang san
// ......
printf("age:%d",pzs->age); //age:24
// ......
getch();
}
(5)结构体变量赋值
结构体变量A与结构体变量B直接用“=”赋值,对应成员的值变化,称为成员赋值。
例子:
#include<stdio.h>
#include<conio.h>
struct person
{
charname[20];
intage;
charemail[50];
};
void main(void)
{
structperson zangsan={"zang san",24,"zs@163.com"};
structperson lisi={"li si",24,"ls@163.com"};
lisi=zangsan;
printf("lisi'sname:%s\n",lisi.name);
getch();
}
//结果:lisi's name:zang san
注意:可以将数组打包成结构体,以便赋值操作。
特殊结构体:
(1)结构体嵌套
即:结构体套结构体,某个结构体的数据成员也是一个结构体变量。
例子:
#include<stdio.h>
struct student
{
char name[20];
struct scorestruct
{
int match;
int English;
}score;
struct infostruct
{
float height;
float weight;
}info;
};
void main(void)
{
struct studentwangwu={"wangwu",{80,96},{175,80}};
printf("wangwu'sname:%s\n",wangwu.name);
printf("wangwu'sEnglish socre:%s\n",wangwu.score.English);
printf("wangwu'sheight:%.1f cm\n",wangwu.info.height);
getch();
}
共用体:由数据成员组成,用关键字union修饰,所有的数据成员共用一块内存
(1)共用体定义
形式:
union 共用体名称(成员标识)
{
存储数据列表(或称成员变量列表)
};
对于型号、价格等参数只取其一,适用共用体。
(2)声明共用体变量
格式: union 共用体名 共用体变量;
定义时,可以同时声明。
例子:(共用体成员访问)
#include<stdio.h>
#include<conio.h>
union computerInfo
{
chartypename[20]; //品牌机类型
floatprice; //组装机价格
};
void main(void)
{
union computerInfo comp1={700};
int type=0;
printf("组装机(输入0)或品牌(输入1)?\n"); //用户选择
scanf("%d",&type);
if(type==0)
{
printf("请输入该组装机的价格\n");
scanf("%f",&comp1.price); //共用体中存储的是价格信息
printf("该组装机的价格是:%.1f\n",comp1.price);
}
if(type==1)
{
printf("请输入该品牌机的型号\n");
scanf("%s",&comp1.typename); //共用体中存储的是型号信息
printf("该品牌机的型号是:%s\n",comp1.typename);
}
getch();
}
(3)共用体赋值
结构体和共用体的内存差异
两种都是复合型的变量,内存形式不同
系统会为结构体变量中的每个数据成员分配不同的地址空间,其数据成员是并列关系;系统为共用体变量中的陈述句成员分配的是同一块内存,每个时刻只有一个数据成员有意义;
(1)结构体变量的内存大小
内存不等于所有数据成员占据内存单元数的和;
例子:
#include<stdio.h>
#include<conio.h>
struct sample1
{
char c; //1字节
short s; //2
float f; //4
};
struct sample2
{
char c; //1
short s; //2
float f; //4
};
void main(void)
{
struct sample1 Example1;
struct sample2 Example2;
printf("结构体变量Example1占据的内存字节数是:%d\n",sizeof(Example1));
printf("结构体变量Example2占据的内存字节数是:%d\n",sizeof(Example2));
getch();
}
输出结果:
结构体变量Example1占据的内存字节数是:8
结构体变量Example2占据的内存字节数是:12
注意:以上例子只是换了顺序,内存字节数却不一样;
原因:C语言用字节对齐机制;
准则:
a. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
b. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要,编辑器会在成员之间加上中间填充字节;
c. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编辑器会在最末一个成员之后加上末尾填充字节。
(2)共同体的大小
原则上,共用体的大小取决于占据最多内存的成员的长度,如:
union Example
{
Char c;
Short s;
Float f;
};
则sizeof(Example)的结果为4,但字节对齐准则3仍然成立,再如:
Union Example
{
Char c[9];
Double d;
};
字符数组c是占内存最多的成员,但sizeof(Example)返回的不是9,而是16,满足准则3,被8整除,后补7字节。
枚举类型:用户自定义类型
(1)枚举类型的定义
关键字enum;
格式:enum 枚举类型名 {枚举常量1[=整型常数],枚举常量2[=整型常数],……};
注意:如果不给枚举常量赋初值,编辑器自动给第一个赋值0,第二个赋值1,逐个加1;
例子:
enum day {Sunday,Monday,……};
以上代码定义了枚举类型day,从Sunday到Saturday,编辑器自动令Sunday为0,Monday为1……
(2)声明枚举变量
如:enum day today;
声明一个day类型的变量today;可以定义同时声明该类型的变量,如下:
Enum day {Sunday,Monday…..} today;
(3)枚举常量是什么
例子:
#include<stdio.h>
#include<conio.h>
enum color{Red,Green,Blue,Black,White}; //枚举类型的定义
void main(void)
{
enum color c1=Blue;
printf("Blue is %d",c1); //枚举常量是整型
getch();
}
//结果:Blue is 2
枚举常量实际上是一些整型数的“名称”,但是不允许直接用数字来定义枚举类型,必须使用合法C标识符作为枚举常量的名字;以下错误写法:enum day {0,1,2,.3,4,5,6,7}.
给类型取个别名——typedef
(1)#define
预处理指令,作简单的替换;
如:#define DP double*
程序中,所有出现DP的地方都被替换为double*,再如:
DP pDouble1,pDouble2; 等价于 double* pDouble1,pDouble2;
(2)typedef
例子:typedef double* DP;
typedef为double* 引入了一个新的助记符DP,在程序中可使用DP声明一个指向double型变量的指针,如:DP pDouble1,pDouble2;
区别:#define不是语句,后面不能加“;” typedef后边需要“;”