结构:STRUCT
结构是由程序员自己设计的一种数据类型,用于描述一个事务的各项数据,由若干个不同的基础数据类型组成。
设计结构:
struct 结构体名
{
类型 成员名;
类型 成员名;
...
};
struct 结构体名
{
类型 成员名;
类型 成员名;
...
}变量名;
struct 结构体名
{
类型 成员名;
类型 成员名;
...
}变量名[n] = {{"mike","w","1234"},{"sony","w","1235"},{...}};
注意:一般结构体名首字母大写
定义结构变量:
struct 结构体名 变量名;
struct 结构体名 变量名 = {"成员一","成员二","成员三"};//成员变量严格按照顺序给
struct 结构体名 变量名 = {.id = 123,.sex = s};//给特定成员名赋值,可以打乱顺序
struct 结构体名 变量名1 = 变量名2;
注意:定义结构变量时,一定不能省略struct,同类型的结构变量可以直接赋值
访问成员变量:
变量名.成员变量
练习:设计一个老师结构体类型、成员姓名,性别,工号,工龄。 定义一个老师结构变量,利用scanf来输入数字,并且显示
结构体变量作为形参时:
由于结构变量的字节数都比较大,值传递的效率比较低,因此都采用传递结构体变量的地址
void show(const struct Teacher* tch)
{
printf("%s %c %d %d",tch->name,tch->sex,tch->id,tch->wage);
}
typedef 重定义结构类型:
typedef struct 结构名 结构名
typedef struct Teacher Teacher
Teahcer tch //无需添加struct关键字
typedef struct Student
{
char name[10];
char sex;
int id;
}Student;//这也是一种写法
注意:一般结构体变量都存储在堆内存,太大了
如何计算结构体的字节数?
1、结构体成员的顺序会影响结构体的总字节大小,如果在设计结构体时,顺序合理可以大大节约内存。
2、内存对齐:假如第一个成员从0地址开始,储存每个成员的地址编号必须能被它的字节数整除,如果不能会填充空字节
3、内存补齐:如果结构体的总字节数,必须是它最大成员字节数的整数倍,如果不是,则在末尾填充空字节。在linux下
超过4字节的都按4字节算,所以double按4字节算.在windows下则实际多少就是多少
#pragma pack(n)//linux 按多少来算 只能往小了改不能超过n<=4(1,2,4),windows n<=默认
联合:UNION
联合与结构的使用方法基本一样,与结构的区别是所有的成员共用一块内存,如果一个成员的值发生改变,其他成员的值也会发生改变。
union Data
{
char ch;
int num;
};
int main()
{
sizeof(union Data) = 4!//默认使用最大类型的地址
}
联合就是用少量的内存对应多个标识符,从而达到节约内存的目的,现在基本用不到。但是得知道
例如:
union Data
{
char ch[10];
int num;
}
union Data d;
sizeof(d) = 12;
注意:联合天然就是对齐的,但是计算联合的字节数时要考虑内存。
如果判断系统是大端还是小端系统?
ABCD 存放 低->高ABCD 大端 高->低 DCBA 小端
union Data
{
char ch;
int num;
}
int main()
{
union Data d={};
d.num = 0x01020304;
printf("%d",d.ch);
if(d.ch == 04)
{
printf("small!");
}
return 0;
}
个人系统一般都是小端系统,unix服务器和网络设备都是大端,网络字节序也是大端模式的数据。
序列化和反序列化
枚举:ENUM
枚举就是一种数据类型,把所有可能出现的值列出来。可以取一个有意义的名字,除此之外的数据。
该类型的变量再等于其他都是非法的(愿望)
枚举就可以看作是一种类型受限的int类型,但是编译器为了效率并不会检查数据的值,所以在c语言中枚举可以当做int类型变量使用。
enum Direction
{
up = 183,
down = 184,
left = 186,
right = 185
};
int main()
{
enum Direction d = up;
printf("%d\n",d);
}
enum Direction{UP=183,DOWN,RIGHT,LEFT};
如果不给成员值,枚举常量的值默认从0开始,逐渐+1,如果某个设置了值,就从那个值开始+1
为什么 使用枚举:
为无意义的数据取一个有意义的名字,提高代码的可读性和安全性(比宏常量更加安全!)
过多使用宏常量会导致冲突可能性增加!