结构体 struct 的深入理解

一、结构体

1.结构体的声明:

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

解析:tag是结构体的标签, struct tag是结构体的类型, member-list是结构体成员的名字,variable-list是创建的结构体变量名

例:

struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

2.结构体的特殊声明:

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

例:

//匿名结构体类型
struct
{
int a;
char b;
float c;
}x;


struct
{
int a;
char b;
float c;
}a[20], *p;

解析:在该代码基础上   p=&x;是错误的,虽然都是匿名结构体,但是因为是不同匿名结构体创立的变量,会被默认成不同类型的结构体。同时匿名结构体只能是在创建struct tag结构体类型时候建立,如果想要同匿名结构体类型的变量,只能在同一个匿名结构体类型的建立下同时建立变量。

3.结构体的自引用:

//代码1
struct Node
{
int data;
struct Node next;
};

解析:该代码是会报错的,因为无法确定该结构体的大小,因为是同类型对同类型的自引用,会陷入套娃无限循环。正确的形式应该是将  struct Node next  改为 struct Node *next;这样一来指针next的大小在默认没有分配动态内存的情况下是4/8字节大小的指针。即可确定结构体的大小。并且可以通过该种结构体自引用的方法模拟实现数据结构中的线性链表。

//代码2
typedef struct
{
int data;
Node* next;
}Node;

解析:该代码也是会报错的,因为该匿名结构体的类型在typedef后重新定义为 Node的类型是出现在Node *next建立之后的,这样就会出现"先有鸡,还是先有蛋的问题",会导致Node* next;的Node是未定义的情况。
 

4.结构体成员的访问:

通过 .  和   ->的访问操作符来访问。

例:

结构体变量.结构体成员名;

结构体变量的地址->结构体成员名;

结构体变量.结构体成员名(若是地址)->指针指向的变量;

结构体变量的地址->结构体成员名(若是结构体).该结构体成员名;

5.结构体变量的定义及初始化:

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};//结构体嵌套初始化

6.结构体对齐(热门话题):

首先,得知道偏移量,结构体中的元素都是得从结构体0位置处开始放置,由offsetof()-宏可可以求出结构体的某个元素距离0位置处的偏移量。

//练习1
struct S1

{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));


//练习2
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));


//练习3
struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3));

解析:结构体对齐即是,结构体的元素是从结构0偏移位置处开始放置的,随后的元素的根据对齐数的整数倍的大小放置的,对齐数是 自身的字节大小数 和 编译器默认对齐数(vs中默认是8,linux中对齐数是自身)的最小的那个作为对齐数,对齐数也可以通过   #pragma pack(1) 进行修改,这里从8修改为1, #pragma pack() 不做修改,就还是默认为8。随后的元素是放在该元素的对齐数的最小整数倍处的。最后放置完之后的总结构体字节大小数要是 所有元素中的最大对齐数的最小整数倍,字节数不够则要填充;


//练习4-结构体嵌套问题
struct S4
{
char c1;
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));

解析:分析同上,只是不同的一点是,嵌套的结构体变量是对齐数,是该嵌套结构体中结构体  (元素)成员的最大对齐数 ,最后 包含嵌套结构体的结构体 的字节数大小是 包括嵌套结构体在内的 所有 (元素)成员的最大对齐数的最小整数倍。

7.结构体传参

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


8.结构体的位段

struct A
    {
        int _a : 2;//_a这个成员只占2个bit位
        int _b : 5;//_b这个成员只占5个bit位
        int _c : 10;
        int _d : 30;
    };//8
    16位机器 - sizeof(int) - 2
    32/64位机器 - sizeof(int) - 4
    
    int main()
    {
        printf("%d\n", sizeof(struct A));
        printf("%d\n", sizeof(struct AA));
    
    
        return 0;
    }

结构体的位段创立的目的是节约空间,是没有结构体对齐的;

如果连续的多个位段加起来小于一个字节数,那这几个位段就会共享一个字节。

多个位段(加起来小于一个字节数) 在加上另一个 位段之后字节数大于1;则另一个位段会存放到下一个字节中。总之,1个字节只能存放总字节数小于或等于1个字节的 (可以是多个,也可以是一个)位段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值