C语言的结构体、位段、联合、枚举

本文详细介绍了C语言中的结构体、位段、联合和枚举的概念及使用方法。结构体用于组合不同类型的数据,位段用于节省空间,联合共享内存空间,枚举提供了一种列举常量的方式,增强了代码的可读性和可维护性。文章还讨论了它们在内存分配、访问成员以及参数传递时的注意事项。
摘要由CSDN通过智能技术生成

一、结构体

1、结构体的声明

1、结构的基础知识。

结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型,描述复杂对象,是我们自己创造出来的一种类型。.

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

比如描述学生,学生包含:名字+年龄+性别+学号这几项信息。比如书名+作者+出版社+定价+书号等。这里只能使用结构体来描述。

2、结构的声明

1)定义结构体类型。例如,描述一个学生,需要一些数据,名字、年龄、性别、电话

  • struct - 结构体关键字,

  • Stu - 结构体标签,

  • struct Stu - 结构体类型,

  • 里面的内容是成员变量,

  • 结尾分号不可缺少

struct Stu

{

//成员变量

charname[20];

shortage;

charsex[5];

chartele[12];

}s1,s2, s3;//s1,s2,s3是三个全局的结构体变量。创建类型之后直接创建三个变量。

2)typedef作用是类型重命名,名字重命名成Stu

typedef struct Stu

{

//成员变量

char name[20];

short age;

char sex[5];

char tele[12];

}Stu;//名字简化成Stu,Stu是类型,可以直接用Stu创建变量

3、类型是用来创建变量的。

1)创建结构体变量

struct Stu s1;//struct Stu - 结构体类型,类型是用来创建变量的。局部结构体变量

Stu s2;//类型重命名成Stu,直接用Stu创建变量

2)初始化:定义变量的同时赋初值。

Stu s = { "张三",18,"男","133666999" };//初始化:定义变量的同时赋初值。

Stu w = { "田七",17,"女","138123564" };//初始化:定义变量的同时赋初值。

4、结构成员的类型。

结构的成员可以是标量、数组、指针,甚至是其他结构体。

1)结构体变量的定义

struct S

{

int a;

char c;

char arr[20];

double d;

};

struct T

{

char ch[10];

struct S s;

char* pc;

};

2)结构体变量的初始化

结构的成员可以是标量、数组、指针,甚至是其他结构体。

char arr[] = "hello world";

struct T t = {"hi",{100,'w',"hello",3.14},arr };//结构体嵌套初始化

printf("%s\n", t.ch);//hi

printf("%s\n", t.s.arr);//hello

printf("%lf\n", t.s.d);//3.14

printf("%s\n",t.pc);//hello world

2、结构体成员的访问

1、结构体变量访问成员。结构变量的成员是通过点操作符·访问的,结构体.成员名

2、结构体指针访问指向变量的成员,操作符:->,结构体指针->成员名

例:

typedef作用是类型重命名,名字重命名成Stu

typedef struct Stu

{

//成员变量

char name[20];

short age;

char sex[5];

char tele[12];

}Stu;//名字简化成Stu,Stu是类型,可以直接用Stu创建变量

void Print1(Stu temp)

{

//结构体变量访问成员,结构变量的成员是通过点操作符(.)访问的。

printf("name: %s\n", temp.name);

printf("age: %d\n", temp.age);

printf("sex: %s\n", temp.sex);

printf("tele: %s\n", temp.tele);

}

void Print2(Stu* ps)

{

//结构体成员访问,还有操作符:->,是针对结构体指针的

printf("name: %s\n", ps->name);

printf("age: %d\n", ps->age);

printf("sex: %s\n", ps->sex);

printf("tele: %s\n", ps->tele);

}

Stu s = { "张三",18,"男","666666" };

//为了打印结构体数据,封装了两个函数,传参可以传s和取地址s(&s)

Print1(s);

Print2(&s);

3、Print1和Print2函数哪个更好?

如果采用Print1函数,实参传给形参,形参实例化之后其实相当于实参的一份临时拷贝。所以,需要拷贝一份一模一样的数据,放在其他内存位置上。会造成空间浪费,时间上效率也低。

如果采用Print2函数,传过去的参数是地址,地址大小是4个字节或者8个字节。所以,无论结构体有多大,Print2函数只需要创建4个字节或者8个字节的结构体指针变量。也可以通过结构体地址改变成员内容。

结论:结构体传参的时候,要传结构体的地址。

4、注意:

函数传参的时候,参数是需要压栈的。

如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。

二、位段

1、位段的声明和结构是类似的

但有两个不同:

1)位段的成员必须是int、unsigned int或signedint。也可以是short、char

2)位段的成员名后边有一个冒号和一个数字。

位段后的数字不能大于32

2、位段的内存分配

1)位段的成员可以是int、unsigned int、signedint或者是char(属于整形家族)类型

2)位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的

3)位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

4)位段是用来节省空间的,开辟的空间由低位向高位使用

例:

#include <stdio.h>

//位段 - 二进制位

struct S

{

int a : 2;//只需要2个bit位,可以表示4种状态

int b : 5;//5个bit位

int c : 10;//10个bit位

int d : 30;//30个bit位

};

int main()

{

//47个bit位 - 大小应该6个字节

//但是位段的空间是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的,所以需要8个字节

struct S s;

printf("%d\n", sizeof(s));//8个字节

return 0;

}

注意:4个字节 = 32个bit位

三、联合(共用体)

联合 - 联合体 - 共用体

联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。

1、联合的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小,因为联合至少得有能力保存最大的那个成员。

在同一时刻,联合体的成员是不能同时使用的

例:

#include <stdio.h>

union Un

{

char c;

int i;

};

int main()

{

union Un u;

printf("%d\n", sizeof(u));//4个字节

//地址是相同的,共用同一块空间

printf("%p\n", &u);

printf("%p\n", &(u.c));

printf("%p\n", &(u.i));

return 0;

}

2、联合大小的计算

联合的大小至少是最大成员的大小。

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。

VS中默认对齐数的值为8

例:

#include <stdio.h>

union Un

{

int a; //大小为4,VS默认对齐数为8,对齐数为4

char arr[5]; //数组的对齐数计算,数组的元素是什么类型,拿数组元素类型计算对齐数。char大小是1,默认是8,→1。

};

int main()

{

union Un u;

printf("%d\n", sizeof(u));//8个字节

return 0;

}

四、枚举

1、枚举顾名思义就是一一列举,把可能的取值一一列举。

比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举。性别有:男、女、保密,也可以一一列举。月份有12个月,也可以一一列举。这里就可以使用枚举了。

2、enumSex,enum Color都是枚举类型。

{}中的内容是枚举类型的可能取值,也叫枚举常量 。这些可能取值都是有值的,默认从0开始,一次递增1,在定义的时候也可以赋初值。

3、我们可以使用#define定义常量,为什么非要使用枚举?

枚举的优点

1)增加代码的可读性和可维护性

2)和#define定义的标识符比较枚举有类型检查,更加严谨。

3)防止了命名污染(封装)

4)便于调试

5)使用方便,一次可以定义多个常量

例:

//枚举类型

enum Sex

{

//枚举的可能取值 - 常量

//常量可以赋初值

MALE = 2,

FEMALE,

SECRET

};

enum Color

{

RED, //0

GREEN,//1

BLUE //2

};

int main()

{

//C语言的源代码-->预编译-->编译-->链接-->可执行程序

enum Sex s = MALE;

enum Color c = BLUE;

printf("%d\n", sizeof(s));//MALE是一个整数,s的大小与整型的大小相同。4个字节

printf("%d %d %d\n", RED, GREEN, BLUE);

printf("%d %d %d\n", MALE, FEMALE, SECRET);

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挨踢牛马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值