ToB企服应用市场:ToB评测及商务社交产业平台
标题:
自界说范例:结构体
[打印本页]
作者:
汕尾海湾
时间:
2024-8-16 19:59
标题:
自界说范例:结构体
一、结构体范例的声明
1、结构体的声明
结构体的声明:
struct tag
{
member-list
};
复制代码
2、结构体变量的创建和初始化
创建一个简单的学生信息结构体
struct student
{
char name[20];
int age;
int score;
};
复制代码
结构体默认初始化的顺序是结构体中创建变量的顺序。
初始化结构体:
struct student
{
char name[20];
int age;
int score;
}s1, s2 = {"李华",18,88}; //第一种初始化
struct student s3 = { "小明",20,100 }; //第二种初始化
int main()
{
struct student s4 = { "张三",15,70 }; //第三种初始化
struct student s5 = { .score = 99,.name = "小红",.age = 22 }; //第四种初始化
return 0;
}
复制代码
3、特殊声明
匿名结构体
struct
{
int a;
char b;
float c;
}x,*p;
复制代码
匿名结构体只允许利用一次,p=&a黑白法请求
4、结构体的自引用
结构体是可以进行自引用的
错误的自引用:
struct stu
{
int a;
struct stu next;
};
正确的自引用:
struct stu
{
int a;
struct stu* next;
};
复制代码
5、typedef重定名结构体
typedef struct Node
{
int data;
struct Node* next;
}Node; //结构体命名为Node
复制代码
二、结构体内存对⻬
1、对齐规则
把握结构体的对齐规则:
结构体中第一个变量首对齐地址是偏移量为0的地址处。
其他成员的对齐变量是范例的整数倍数的地址处。vs默认对齐量为8,linux中gcc没用对齐数,对齐数就是自身大小
结构体的总大小为最大对齐数
对于嵌套结构体,嵌套结构中对齐量是结构体中最大的一个变量整数倍数地址处,而竣事时是嵌套结构体的整数倍数
如盘算int 对齐数 4 8 4 int范例的大小对比默认值大小,谁小选谁是对齐数
//练习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));
//练习4-结构体嵌套问题
struct S4
{
char c1;
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));
复制代码
在以上例题中,我们发现结构体中开辟的空间有许多空间被浪费了,以是在创建范例时,需要合理的排序
在例题1与例题2中,创建的范例是一样的,就由于范例创建的顺序不一样,导致占用内存不一样。
尽量使变量小的范例排在前面
2、为什么存在内存对齐
1、平台移植问题:不是全部的硬件平台都能访问任意地址上的任意数据
2、性能问题:假如没用地址对齐,处理器需要作两次的内存访问,而对齐的内存只需要访问一次
总结来说:拿空间换时间
3、修改默认对齐数
通过利用#pragma这个预处理指令,可以改变编译器的默认对齐数
#pragma pack(4)//设置对齐数变为4
struct stu
{
char a;
int b;
char d;
double c;
};
#pragma pack()//取消设置的对齐数,还原默认
int main()
{
printf("%zd\n", sizeof(struct stu));
}
复制代码
三、结构体传参
struct stu
{
char name[10];
int age;
};
struct stu s1 = { "xiaoming",28 };
void print1(struct stu s1)
{
printf("%d,%s\n", s1.age, s1.name);
}
void print2(struct stu* s1)
{
printf("%d,%s\n", s1->age, s1->name);
}
int main()
{
print1(s1); //传值调用
print2(&s1); //传址调用
return 0;
}
复制代码
输出:
结构体可以利用传值也可以利用传址,优先选用传址调用,如许不需要开辟新的空间,可以大大提高代码的运行效率。
四、结构体实现位段
1、什么是位段
位端可以限制结构体中创建变量占用内存的大小
利用位段时,成名必须是unsigend int,int,sigent int,在c99中其他成员可以利用位段
位段的创建在成员名后面加上一个冒号跟一个数字。
比如:
struct stu
{
int _a : 4;
int _b : 2;
int _c : 1;
int _d : 30;
};
复制代码
2、位段的内存分配
位段的成员可以是int,unsigent int ,signet int,char范例
位段上的空间是以四个字节跟一个字节进行开辟空间的
位段无法跨平台利用
struct stu
{
int _a : 4;
int _b : 10;
int _c : 1;
int _d : 20;
};
int main()
{
printf("%zd\n", sizeof(struct stu));
return;
}
复制代码
输出:
假如没用位段,那么4个int范例的字节大小位12
位段是如何开辟空间的,如下:
3、位段的跨平台问题
1、int位段是被当成有符号位还是无符号位是不确定的
2、位段中最大数是不确定的(有16位机器,假如设置段位超过16比特,那么就会出问题,32位机器同意也是)
3、内存是从左到右分配,还是从右到左分配是不确定的(vs是从右到左分配)
4、当一个结构体包罗两个位段时,第二个位段成员比较大,无法容纳第一个尾端剩余空间的时间,是否会舍弃剩余空间,这是不确定的。
总结:位段可以很好的节流空间,但存在跨平台问题
4、位段的应⽤
下图是⽹络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要⼏个bit位就能描述,这⾥使⽤位段,可以或许实现想要的结果,也节流了空间,如许⽹络传输的数据报⼤⼩也会较⼩⼀些,对⽹络的畅通是有资助的。
5、位段使⽤的留意事项
无法获取比特位的地址。
无法直接利用scanf来输入位段,但是可以赋值位段
struct stu
{
int _a : 4;
int _b : 10;
int _c : 1;
int _d : 20;
};
int main()
{
struct stu s = { 0 };
int n = 0;
scanf("%d", &n);
s._a = n;
return;
}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4