自定义类型:结构体

结构体的声明和使用

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

struct tag
{
    member-list;
}variable-list;

实际使用起来:

//假设这里要创建一个学生结构体
struct stu
{
    char name[20];
    int age;
};

stu就是这个结构体的结构体标签

name和age是结构体的成员变量

结构体是自定义类型,所以在这样声明之后,struct stu 就和int,char一样是一个数据类型。

用struct stu来创建一个变量a

struct stu a;

或者在声明结构体类型时,就能顺带创建变量

struct stu
{
    char name[20];
    int age;
}s1,s2;

s1,s2就是通过结构体创建的变量(这里时全局变量)

鉴于结构体类型struct stu长度太长,我们可以用typedef来重命名这个类型

typedef struct stu STU;

把struct stu重命名为STU

或者在声明结构体类型时就重命名

typedef struct stu
{
    char name[20];
    int age;
};STU

(这里的STU在;后面,注意不是创建变量)

用重命名的结构体类型来创建变量:

STU s1,s2;

匿名结构体类型

struct
{
    char name[20];
}s1;

像这样声明结构体时没有结构体标签的不完全声明。

这样的不完全声明,使得仅仅在声明结构体时才能创建变量(s1),后面就无法再用这个结构体类型了(除非在声明时又拿typedef重命名了,虽然很多此一举)。

这个操作一般用于一些只使用一次的结构体类型。

(哪怕是两个成员变量完全相同的匿名结构体类型,也会被判别成不同的类型,比如用这两个匿名结构体类型分别创建变量,这两个变量的类型就是不同的)

结构体初始化变量

1.在结构体声明时初始化变量,p={}内的值,依次为p的成员变量的初始化 

struct point
{
    int x;
    int y;
}p={10,20};

2.用结构体类型初始化变量

struct point p={10,20};

如果结构体的成员类型复杂,甚至是结构体类型

struct S
{
    int mun;
    char ch;
    struct point p;
    float d;
};

struct S a={100,'w',{2,5},3.14f};

在a={}内依次初始化,结构体类型用{}括起来,在写对应的struct point里的成员变量

如果不想按照顺序进行初始化,则要带上对应的成员变量,还要有"."操作符

struct S s2={.d=3.14f,.p.x=2,.p.y=5,.ch='w',.num=100};

结构体内存对齐

结构体作为一种类型,和int,char一样也是有大小的,但是结构体的大小不单单取决于成员变量的类型,还取决于成员变量的顺序,以及不同环境下也会有影响。

结构体是按一定的对齐规则进行储存的。

以下是一个结构体和内存,每一小格是一个字节(byte)

电脑进行存储时,会在内存里调一个位置开始存放,我们以这个开始存放的点为基准,下面的按编号的每一格,就是0偏移处、1偏移处、2偏移处.......。

1.结构体的第一个成员,对齐到结构体在内存中存放位置的0偏移处

2.从第二个成员开始,每个成员都要对其到一个对齐数的整数倍处。

      对其数:结构体成员自身的大小和默认对齐数中的较小值。(默认对其数,vs环境下是8,linux和gcc下没有默认对齐数,所以对其数就是结构体成员大小)。

 

3.结构体的大小是所有成员中最大对齐数的倍数。

现在最大对齐数是4,而从0到11所占的字节数是12,是4的整数倍,所以结构体大小是12字节。

(假如最后一个成员是char型,那么对齐完所占的字节数是9个,不是4的倍数,就要往下找,直到找到4的倍数作为结构体大小。)

4.结构体嵌套了结构体的情况,例如struct a嵌套了struct b(struct b是struct a的成员)把struct b看成正常的数据类型,它的对齐数是struct b的成员中的最大对齐数,所占的大小是struct b的大小。基于此按照上面的操作进行对齐。

-->在设计结构体时,让占用空间小的成员集中放在一起,能减少空出来的空间,以减少空间。

对齐的意义在于用空间换取读取效率。在电脑读取完第一个变量后,接下来一个成员变量在读取时,要读取完一整个成员变量才能判别出是什么类型,即每走一步都要进行一次判断,判断是什么变量。对齐了的话从对齐的位置就能直接知道成员变量的类型,但是会因为对齐多用一些空间。

修改默认对齐数

在vs里默认对齐数是8,但是有方法可以修改默认对齐数

#pragma pack(4) //设置默认对齐参数为4
#pragma pack()  //返回为默认

结构体传参

struct S
 {
 int data[1000];
 int num;
 };
 struct S s = {{1,2,3,4}, 1000};

 //结构体变量传参
void print1(struct S s)
 {
 printf("%d\n", s.num);
 }

 //结构体变量地址传参
void print2(struct S* ps)
 {
 printf("%d\n", ps->num);//地址用->
 }

 int main()
 {
 print1(s);  //传结构体
print2(&s); //传地址
return 0;
 }

在传结构体变量和传结构体变量地址间,选传地址,因为函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的 下降。

总之,首选传地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值