学习小结
c语言自定义类型的学习笔记汇总
//自定义类型:结构体,枚举,联合
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//结构体
//结构是一些值的集合,这些值被称为成员变量,结构的每个成员可以是不同类型的变量
//声明一个结构体类型
//struct Stu
//{
// char name[20];
// char tele[12];
// char sex[10];
// int age;
//
//}s4, s5, s6;
//struct Stu s3;//全局变量
//int main()
//{
// //创建的结构体变量 s1 s2
// struct Stu s1;
// struct Stu s2;
// return 0;
//}
//匿名结构体类型(不建议使用)
//struct
//{
// char tele[12];
// char sex[10];
// int age;
//}sa;
//struct
//{
// char tele[12];
// char sex[10];
// int age;
//}*psa;//变成结构体指针
//int main()
//{
// psa = &sa;//(不合法,不合规矩的)
// //编译器会把上面的两个声明当成完全不同的两个类型,所以是非法的
// return 0;
//}
//结构体的自引用
//struct Node
//{
// //数据域
// int date;
// //指针域
// struct Node* next;//存放下一个节点的地址
//};
//int main()
//{
// sizeof(struct Node);
// return 0;
//}
//注意:结构体的自引用不能包含结构体本身的类型,可以用地址代替
//结构体类型重命名
//typedef struct Node
//{
// int date;
//}Node;
//int main()
//{
// struct Node n1;
// Node n2;
// //以上两种写法都可以
// return 0;
//}
//结构体变量的定义和初始化
//struct Point
//{
// int x;
// int y;
//}p1; //声明类型的同时定义变量p1
//struct Point p2; //定义结构体变量p2
//struct T
//{
// double weight;
// short age;
//};
//struct S
//{
// char c;
// int a;
// double d;
// char arr[20];
// struct T st;
//};
//int main()
//{
// //结构体的初始化与结构体成员的访问
// //struct S s = { 'c',100,3.14,"hello bit"};
// //printf("%c %d %lf %s", s.c, s.a, s.d, s.arr);//c 100 3.140000 hello bit
//
// //结构体中使用结构体
// struct S s = { 'c',100,3.14,"hello",{55.6,30} };
// printf("%lf", s.st.weight);//55.600000
//
// return 0;
//}
//结构体内存对齐
//struct S1
//{
// char c1;
// int a;
// char c2;
//};
//struct S2
//{
// char c1;
// char c2;
// int a;
//};
//int main()
//{
// struct S1 s1 = { 0 };//将所有值初始化为0
// printf("%d\n", sizeof(s1));//12
// struct S2 s2 = { 0 };
// printf("%d\n", sizeof(s2));//8
//
// return 0;
//}
//例题
//typedef struct s3
//{
// double d;//双精度浮点数大小为8个字节
// char c;//字符大小为1个字节
// int i;//整形四个字节
//}s3;
结构体嵌套问题
//typedef struct s4
//{
// char c1;
// s3 c2;
// double d;
//}s4;
//int main()
//{
// printf("%d\n", sizeof(s3));//16
// printf("%d\n", sizeof(s4));//32
// return 0;
//}
//注意
//1、第一个成员在结构体变量偏移为0(相差0)的地址处
//2、其他成员变量要对齐到某个数字(对其数)的整数倍的地址处
//注意:对齐数指:编译器默认的一个对齐数与该成员大小的较小值
//vs编译器的值为8
//3、结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
//4、如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
//修改默认对齐数
//#pragma pack(4)//设置默认对齐数为4
//struct S
//{
// char c1;//1
// //7 浪费了7
// double d;//8
//};
//#pragma pack()//取消设置的默认对齐数
//int main()
//{
// struct S s;
// printf("%d\n", sizeof(s));//12 如果不加pragma的结果是16
// return 0;
//}
//#pragma pack(1)//设置默认对齐数为1
//struct S
//{
// char c1;//1
// //7 浪费了7
// double d;//8
//};
//#pragma pack()//取消设置的默认对齐数
//int main()
//{
// struct S s;
// printf("%d\n", sizeof(s));//9
// return 0;
//}
//注意:结果在对齐方式不合适的时候,我们可以自己更改默认对齐数
//Offsetof宏 用于计算结构体成员的偏移
//格式offsetof(struct Name, memberName);
//#include<stddef.h>
//struct S
//{
// char c;
// int i;
// double d;
//};
//int main()
//{
// printf("%d\n", offsetof(struct S, c));//0
// printf("%d\n", offsetof(struct S, i));//4
// printf("%d\n", offsetof(struct S, d));//8
// return 0;
//}
//结构体传参
//struct S
//{
// int a;
// char c;
// double d;
//};
//void Init(struct S* ps)
//{
// ps->a = 100;
// ps->c = 'w';
// ps->d = 3.14;
//}
//void Print1(struct S tmp)//因为只是打印,不需要修改
//{
// printf("%d\n", tmp.a);//100
// printf("%c\n", tmp.c);//w
// printf("%lf\n", tmp.d);//3.140000
//}
//void Print2(struct S* ps)
//{
// printf("%d\n", ps->a);//100
// printf("%c\n", ps->c);//w
// printf("%lf\n", ps->d);//3.140000
//}
//int main()
//{
// struct S s;
// Init(&s);//结构体传参对s的内容进行初始化
// Print1(s);
// Print2(&s);
//
// s.a = 100;
// s.c = 'w';
// s.d = 3.14;
// printf("%d\n", s.a);//100
// printf("%c\n", s.c);//w
// printf("%lf\n", s.d);//3.140000
// return 0;
//}
//位段
//位段的声明和结构是类似的,有两个不同
//1、位段的成员必须是int,unsugned int或signed int或者char(整形家族类型)类型
//2、位段的成员名后边有一个冒号和一个数字
//struct S
//{
// int a : 2;//意思是a只需要两个比特位的内存存储就可以了,以下同理
// int b : 5;
// int c : 10;
// int d : 30;
// //总共48个比特位
//};
//int main()
//{
// struct S s;
// printf("%d\n", sizeof(s));//8
// return 0;
//}
//位段的内存分配
//位段的空间是按照需要以四个字节(int)或者1个字节(char)的方式来开辟的
//struct S
//{
// char a : 3;
// char b : 4;
// char c : 5;
// char d : 4;
//};
//int main()
//{
// struct S s;
// s.a = 10;
// s.b = 20;
// s.c = 3;
// s.d = 4;
// printf("%d\n", sizeof(s));//3
// return 0;
//}
//注意:跟结构体相比,位段可以达到同样的效果,但是可以很好节省空间,但是有跨平台的问题存在
//枚举
//枚举顾名思义就是——列举
//枚举类型的定义
//enum Day//星期 枚举类型
//{
// //枚举的可能取值 - 常量
// Mon,
// Tues,
// Wed,
// Thur,
// Fri,
// Sat,
// Sun
//};
//enum Sex//枚举类型
//{
// //枚举的可能取值
// boy=2,
// girl
//};
//enum Color
//{
// Ret,
// Green,
// Blue
//};
//int main()
//{
// //赋值只能赋予枚举列表中的元素
// enum Sex s = boy;
// s = girl;
// enum Color c = Blue;
// printf("%d %d %d\n", Ret, Green, Blue);//0 1 2
// printf("%d %d\n", boy, girl);//2 3
// //注意:枚举列表中的元素第一个默认从零开始,依次往下增加1(默认情况下)
// return 0;
//}
//联合 - 联合体(共用体)
//联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间(所以联合体也叫共用体)
//
//union Un
//{
// char c;
// int i;
//};
//int main()
//{
// union Un u;
// printf("%d\n", sizeof(u));//4
// printf("%p\n", &u); //00000061764FF7F4
// printf("%p\n", &u.c); //00000061764FF7F4
// printf("%p\n", &u.i); //00000061764FF7F4
// //特征是这些成员共用同一块空间,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少有能力保存最大的那个成员)
// //同等时间内只能用一个
// return 0;
//}
//注意:联合体的大小至少是最大成员的大小
//判断大小端
//第一种
//int main()
//{
// int a = 1;
// if (*(char*)&a == 1)
// {
// printf("小端");
// }
// else
// {
// printf("大端");
// }
// //低地址 高地址
// //……[][][][11][22][33][44][][][]…… 大端存储模式
// //……[][][][44][33][22][11][][][]…… 小端存储模式
// return 0;
//}
//第二种
//int chack_sys()
//{
// union Un
// {
// char c;
// int i;
// }u;//利用联合体共用同一块空间的特点实现
// u.i = 1;
// return u.c;//返回第一个字节
// //返回1是小端
// //返回0是大端
//}
//int main()
//{
// int ret = chack_sys();
// if (ret == 1)
// printf("小端");
// else
// printf("大端");
// return 0;
//}
//union Un
//{
// int a;//4
// char arr[5];//5
//};
//int main()
//{
// union Un u;
// printf("%d\n", sizeof(u));//8 内存对齐
// return 0;
//}
//联合体大小的计算
//联合体的大小至少是最大成员的大小
//当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
以上代码均在vs2022环境下编译