结构体的学习与运用

定义及声明

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

比如,描述一个学生:

struct Student//结构体名

 {

        char name[20];//名字

        int age;//年龄

        char sex[5];//性别

        char id[20];//学号       

 }(创建变量名);

特殊声明 

在声明结构的时候,可以不完全的声明。

匿名结构体类型:

struct

{

int a;

char b;

float c;

}x;

struct

{

int a;

char b;

float c;

}a[20], *p;

以上两结构在声明时省略了结构体标签

编译器会把上⾯的两个声明当成完全不同的两个类型,所以p与&x不是同一类型

匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。

结构的⾃引⽤ :

struct Node

{

        int data;

        struct Node next;

};

这不是合法指令,这样的结构体变量的⼤ ⼩就会⽆穷的⼤,是不合理的。

正确的写法:

struct Node

{

        int data;

        struct Node* next;

}; 

在结构体⾃引⽤使⽤的过程中,夹杂了typedef对匿名结构体类型重命名,也容易引⼊问题:

typedef struct

{

        int data;

        Node* next;

}Node; 

这是不⾏的,因为Node是对前⾯的匿名结构体类型的重命名产⽣的,但是在匿名结构体内部提前使 ⽤Node类型来创建成员变量,这是不⾏的。

解决⽅案如下:定义结构体不要使⽤匿名结构体了 

typedef struct Node

{

        int data;

        struct Node* next;

}Node;

 结构体变量的创建和初始化

struct Point

{

int x;

int y;

}p1; //声明类型的同时定义变量p1

struct Point p2; //定义结构体变量p2

struct Point p3 = {x, y};//初始化:定义变量的同时赋初值。

struct Stu //类型声明

{

char name[15];//名字

int age; //年龄

};

struct Stu s = {"zhangsan", 20};//初始化

struct Node

{

int data;

struct Point p;

struct Node* next;

}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化

struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化

初始化格式也可以是这样:

struct Stu

{

char name[15];

int age;

};

struct Stu s = {.age=20, .name="zhangsan"}; 

结构成员访问操作符有两个⼀个是 . ,⼀个是 -> 

结构体变量.成员变量名

结构体指针—>成员变量名

结构体内存的对齐

1. 结构体的第⼀个成员对⻬到相对结构体变量起始位置偏移量为0的地址处

2. 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。 对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。 - VS中默认的值为8 - Linux中没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

3. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的 整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

比如:

struct S1

{

        char c1;

        int i;

        char c2;

};

 c1(字符类型)从0开始占了一字节,i(整形类型)从4的倍数4开始占四字节,c2(字符类型)从8开始占一字节。总计大小为最大对齐数4的倍数8字节。

所以想节省空间就要改变成员创建的顺序。

修改默认对齐数

#pragma 这个预处理指令,可以改变编译器的默认对⻬数。

结构体在对⻬⽅式不合适的时候,我们可以⾃⼰更改默认对⻬数。

#pragma pack(1)//设置默认对⻬数为1

#pragma pack()//取消设置的默认对⻬数,还原为默认

结构体传参

 

因为函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。 如果传递⼀个结构体对象的时候,结构体过⼤,参数压栈的的系统开销⽐较⼤,所以会导致性能的下 降。

所以结构体传参的时候,要传结构体的地址。

位段

1.位段的成员可以是 int unsigned int signed int 或者是 char 等类型

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

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

冒号后面跟的是给予成员的比特位数,这样大大节省了空间。

ps:位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位 置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的。 所以不能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊ 放在⼀个变量中,然后赋值给位段的成员。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值