结构体(struct)是由一批相同或不同类型的数据组合而成的数据类型。结构体通常用来表示类型不同但是又相关的若干数据,其定义是由程序设计者自己根据实际需求进行。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构,其成员一般用名字访问
例如定义一个学生
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢
struct stu {
char name[20];
int age;
char sex[20];
}s1 = {"lisi",20,"nan"} ;//直接在结构体后面创建结构体变量,并按照结构体成员顺序初始化
struct stu s2 = { "lis",22,"nan" };//在函数外创建全局结构体变量,并按照结构体成员顺序初始化
int main(){
printf("name=%s,age=%d,sex=%s\n", s1.name, s1.age, s1.sex);
printf("name=%s,age=%d,sex=%s\n",s2.name,s2.age,s2.sex);
struct stu s3 = { .sex = "nv",.age = 24,.name = "wanh" };
//在函数内部创建结构体变量,并按照指定顺序初始化
printf("name=%s,age=%d,sex=%s\n", s3.name, s3.age, s3.sex);
}
//输出
//name = lisi, age = 20, sex = nan
//name = lis, age = 22, sex = nan
//name = wanh, age = 24, sex = nv
struct s
{
int a;
int b;
int c;
};//表面了有一个名叫struct s的结构体
//如果想要定义一个结构体变量
struct s s1;
//使用typetef
typedef struct s
{
int a;
int b;
int c;
}s;//表面了struct s的结构体被重命名为s
//这里定义变量就明了点
s s2;
匿名结构体是指没有名字的结构体,通常被用来表示简单的数据结构或者临时的数据类型。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次,所以下面代码会报错。
struct
{
int a;
char b;
double c;
}arr[20],*p;//匿名结构体
int main() {
p = &s1;
//warning C4133: “=”: 从“*”到“*”的类型不兼容
return 0;
}
⾸先得掌握结构体的对⻬规则:
1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址。
2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
对⻬数 = 编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。VS 中默认的值为 8 ,Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。结构体的内存对⻬是拿空间来换取时间的做法
举个例子
struct s1
{
char c1;//第一个元素对齐偏移量0的地址,放到偏移量1
int i;//元素大小和编译器默认对齐数比较出最小值是4,从偏移量4 开始放置字节,放到偏移量8
char c2;元素大小和编译器默认对齐数比较出最小值是1,从偏移量9 开始放置字节,放到偏移量9
};
int main() {
printf("%d", sizeof(struct s1)); //12总大小是选出最大偏移量的倍数4,最后放到12
//格式字符串“% d”需要类型“int”的参数,
// 但可变参数 1 拥有了类型“size_t”,用"%zd"不警告
}
struct S2
{
char c1;//1
char c2;//1
int i;//4最小,要在4的整数倍存放四个字节,就到偏移量8了
}//最终结果就是最大的对齐数是4,结果是四的倍数
printf("%d\n", sizeof(struct S2));
//练习3
struct S3
{
double d;//8
char c;//9
int i;//12开始放到16之前,最终结果是8的倍数就是16
};
printf("%d\n", sizeof(struct S3));
//练习4-结构体嵌套问题
struct S4
{
char c1;//1
struct S3 s3;//从自己最大对齐数的倍数开始存放,存自身的字节,上面算出16字节,
double d;
};
printf("%d\n", sizeof(struct S4));
#include
#pragma pack(1)//
struct s {
char a;
int b;
char c;
};
int main() {
printf("%d ", sizeof(struct s));//修改默认对齐数之前是12,修改完是6
return 0;
}
因为在调用函数的时候如果传递参数,因为形参是实参的临时拷贝,如果传递结构体数据过大,参数压栈的系统开销比较大,所以会导致性能降低
struct S {
int data[1000];//data数据的意思
int num;
};
struct S s={{1,2,3,1},1001 };
void print1(struct S s) {
printf("%d\n", s.num);
}
void print2(struct S *s) {
printf("%d\n", s->num);
}
int main() {
print1(s);
print2(&s);
return 0;
}
联合体,也叫共用体,类似与结构体,可以存放多个不同类型的元素,但是编译器只为字节最大的类型开辟内存空间,所有类型会公用一片空间,当联合体的一个值被改变其他值也会跟着改变
#include
union an
{
char c;
int a;
};
int main() {
//联合体变量的定义,可以说明公用一片空间
union an a = { 0 };
printf("%d ", sizeof(union an));//4
return 0;
}
#include
//联合类型的声明
union Un
{
char c;
int i;
};
int main()
{
//联合变量的定义,当联合体的一个值被改变其他值也会跟着改变
union Un un = { 0 };
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);//输出11223355
return 0;
}
这串代码可以证明联合体内部所有元素地址都是一样的
union Un
{
char c;
int i;
};
int main()
{
//联合变量的定义
union Un un = { 0 };
printf("%p\n", &(un.i));
printf("%p\n", &(un.c));
printf("%p\n", &un);
return 0;
}1
联合体内存最小也是里面最大成员的大小,最大成员大小不是最大对齐整数倍的时候,就要对齐到最大对齐数的整数倍。
#include
union Un1
{
char c[5];//5
int i;//4最大对齐数是4,最大内存是5,所以8
};
union Un2
{
short c[7];//14最大对齐数是4,最大内存是14所以最后16
int i;//4
};
int main()
{
//下⾯输出的结果是什么?
printf("%d\n", sizeof(union Un1));//8
printf("%d\n", sizeof(union Un2));//16
return 0;
}
小端保存就是地址由低到高展示情况下,数据存放是把数据的低位放到内存的低位,数据的高位放到内存的高位,小端保存就是地址由低到高展示情况下,数据存放是把数据的低位放到内存的高位,数据的高位放到内存的低位。
int check_sys() {
union un
{
int a;
char b;
}c;
c.a = 1;
return c.b;
}
int main() {
if (check_sys() == 1) {
printf("小端");
}else{
printf("大端");
}
}
顾名思义可以理解为列举,把所有可能的取值都列举出来,例如星期,性别,月份,三原色
enum day
{
sun,//默认0,下面依次加一
mon,
tues,
wed,
thur,
fri,
sat //6
};
enum sex {
male,//男
female,//nv
secret//秘密
};
enum Color//颜⾊
{
RED = 2,//可以赋初值。
GREEN = 4,
BLUE = 8
};
枚举可以用来帮助用户更好的阅读代码,例如,下面这串代码,直接展示不要枚举类型也可以运行,但是在读代码的时候就不方便理解其作用。
switch (input) {
case 0:
printf("退出程序\n");
break;
case 1:
Addcon(&con);
break;
case 2:
DelCon(&con);
break;
case 3:
searchcon(&con);
break;
case 4:
ModifyCon(&con);
break;
case 5:
SortCon(&con);
break;
case 6:
Printcon(&con);
break;
default:
printf("输入错误请重新输\n");
break;
}
加上枚举后就可以很直观的理解其代码的作用
enum option//
{
EXIT,//0
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
PRINT//6
};
switch (input) {
case EXIT:
printf("退出程序\n");
break;
case ADD:
Addcon(&con);
break;
case DEL:
DelCon(&con);
break;
case SEARCH:
searchcon(&con);
break;
case MODIFY:
ModifyCon(&con);
break;
case SORT:
SortCon(&con);
break;
case PRINT:
Printcon(&con);
break;
default:
printf("输入错误请重新输\n");
break;
}
好了以上就是带你重新学习结构体、联合体、枚举的所有内容啦,如果对你有帮助请三连,也请大佬多多指正