带你重新学习结构体、联合体、枚举

结构体

介绍结构体

结构体(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));

用program修改自身最大对齐数

#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;
}

好了以上就是带你重新学习结构体、联合体、枚举的所有内容啦,如果对你有帮助请三连,也请大佬多多指正

带你重新学习结构体、联合体、枚举_第1张图片

你可能感兴趣的:(c语言,数据结构,c语言,算法,开发语言,c#,改行学it)