c语言->浅学结构体
2023-12-15 20:20:17
系列文章目录
文章目录
前言
?作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉
🍎个人主页:橘橙黄又青_C语言,函数,指针-CSDN博客
目的:学习结构体基础内容,联合体的内容和与结构体的区别,枚举类型的理解。
1. 结构体类型的声明
struct tag
{
member-list;
}variable-list;
例如描述?个学?:
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢
1.1.结构体变量的创建和初始化
#include <stdio.h>
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
};
int main()
{
//按照结构体成员的顺序初始化
struct Stu s = { "张三", 20, "男", "20230818001" };
printf("name: %s\n", s.name);
printf("age : %d\n", s.age);
printf("sex : %s\n", s.sex);
printf("id : %s\n", s.id);
return 0;
}
也可以按照指定循序初始化
struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = "?
printf("name: %s\n", s2.name);
printf("age : %d\n", s2.age);
printf("sex : %s\n", s2.sex);
printf("id : %s\n", s2.id);
1.2 结构的特殊声明
在声明结构的时候,可以不完全的声明看:
//匿名结构体类型
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
上?的两个结构在声明的时候省略掉了结构体标签(tag)。
那么问题来了?
//在上?代码的基础上,下?的代码合法吗?
p = &x;
警告:
编译器会把上?的两个声明当成完全不同的两个类型,所以是?法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上
只能使??次
。
1.3 结构的?引?
在结构中包含?个类型为该结构本?的成员是否可以呢?
?如,定义?个链表的节点:
struct Node
{
int data;
struct Node next;
};
上述代码正确吗?如果正确,那
sizeof(struct Node)
是多少?
仔细分析,其实是不?的,因为?个结构体中再包含?个同类型的结构体变量,这样结构体变量的? ?(字节)就会?穷的?,
是不合理的
。
正确的?引??式:
struct Node
{
int data;
struct Node* next;
};
这个到后面数据结构会细讲。、
1.4typedef 对匿名结构体类型重命名
在结构体?引?使?的过程中,夹杂了
typedef
对匿名结构体类型重命名,也容易引?问题,看看
下?的代码,可?吗?
typedef struct
{
int data;
Node* next;
}Node;
答案是不?的,因为Node是对前?的匿名结构体类型的重命名产?的,
但是在匿名结构体内部提前使?Node类型来创建成员变量
,这是不?的。
解决?案如下:定义结构体不要使?匿名结构体了
typedef struct Node
{
int data;
struct Node* next;
}Node;
2. 结构体内存对?
现在我们深?讨论?个问题:计算结构体的??。
这也是?个特别热?的考点: 结构体内存对?。
2.1 对?规则
?先得掌握结构体的
对?规则
:
1. 结构体的第?个成员对?到和结构体变量起始位置偏移量为0的地址处。2. 其他成员变量要对?到某个数字(对?数)的整数倍的地址处。对?数 = 编译器默认的?个对?数 与 该成员变量??的较?值。3. 结构体总??为最?对?数(结构体中每个成员变量都有?个对?数,所有对?数中最?的)的 整数倍。4. 如果嵌套了结构体的情况,嵌套的结构体成员对?到??的成员中最?对?数的整数倍处,结构 体的整体??就是所有最?对?数(含嵌套结构体中成员的对?数)的整数倍。
扩展:
- VS 中默认的值为 8- Linux中 gcc 没有默认对?数,对?数就是成员??的??
?接下来用4个例子说明:
案例1:
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));//12
分析:
案例2:
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));//8
分析:
?
案例3:
struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3));//32
分析:
?案例4:
练习4-结构体嵌套问题
struct S4
{
char c1;
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));
分析:
2.2 为什么存在内存对?? ?
1.
平台原因 (移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定 类型的数据,否则抛出硬件异常。
2.
性能原因:
数据结构(尤其是栈)应该尽可能地在?然边界上对?。原因在于,为了访问未对?的内存,处理器需要 作两次内存访问;?对?的内存访问仅需要?次访问。假设?个处理器总是从内存中取8个字节,则地 址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对?成8的倍数,那么就可以 ??个内存操作来读或者写值了。否则,我们可能需要执?两次内存访问,因为对象可能被分放在两 个8字节内存块中。
总体来说:结构体的内存对?是拿空间来换取时间的做法。
2.3 修改默认对?数
#pragma 这个预处理指令,可以改变编译器的默认对?数,案例:
#include <stdio.h>
#pragma pack(1)//设置默认对?数为1
struct S
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的对?数,还原为默认
int main()
{
printf("%d\n", sizeof(struct S));
return 0;
}
这样就可以修改默认的对齐数了。
结构体在对??式不合适的时候,我们可以??更改默认对?数。
3. 结构体传参
struct S
{
int data[1000];
int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
//第1种
void print1(struct S s)
{
printf("%d\n", s.num);
}
//第2种
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); //传结构体
print2(&s); //传地址
return 0;
}
上?的
print1
和
print2
函数哪个好些?
答案是:?选print2函数。
原因:
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。如果传递?个结构体对象的时候,结构体过?,参数压栈的的系统开销?较?,所以会导致性能的下 降。
结论:?
?也就是说:如果结构体过?,开辟空间大,不利于计算机的结束效率。
结构体传参的时候,要传结构体的地址。
4. 结构体实现位段
位段的声明和结构是类似的,有两个不同:
1.
位段的成员
必须是 int、unsigned int 或signed int
,在C99中位段成员的类型也可以
选择其他类型。
2.
位段的成员名后边
有?个冒号和?个数字(bit位个数)
。
?如:
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
A就是?个位段类型。
那位段A所占内存的??是多少?
printf("%d\n", sizeof(struct A));
这是为什么呢?接下来我们来学习位段的内存分配。
4.2 位段的内存分配
1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的?式来开辟的。3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使?位段。
举一个例子,位段是如何开辟空间的呢:
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
?分析:
总结:vs从左向右使用,遵循结构体对齐数原则,如果剩余的空间不够就浪费一定空间,开辟新空间。
4.3 位段的跨平台问题
1. int 位段被当成有符号数还是?符号数是不确定的。2. 位段中最?位的数?不能确定。(16位机器最?16,32位机器最?32,写成27,在16位机器会 出问题。3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。4. 当?个结构包含两个位段,第?个位段成员?较?,?法容纳于第?个位段剩余的位时,是舍弃 剩余的位还是利?,这是不确定的。
?总结:跟结构相?,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。
4.4位段使?的注意事项
位段的?个成员共有同?个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位 置处是没有地址的。内存中每个字节分配?个地址,?个字节内部的bit位是没有地址的。
所以不能对位段的成员使?&操作符,这样就不能使?scanf直接给位段的成员输?值,只能是先输? 放在?个变量中,然后赋值给位段的成员。
如下:
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
int main()
{
struct A sa = {0};
scanf("%d", &sa._b);//这是错误的
//正确的?范
int b = 0;
scanf("%d", &b);
sa._b = b;
return 0;
}
结构体的学习就到这里了,都看到这里了,点一个赞吧,谢谢。?
文章来源:https://blog.csdn.net/chendemingxxx/article/details/134906255
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!