前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一篇文章介绍结构体

一篇文章介绍结构体

作者头像
用户11039545
发布2024-03-28 17:23:56
790
发布2024-03-28 17:23:56
举报
文章被收录于专栏:c语言c语言

这段时间迷迷糊糊学了指针,学校的考试范围还有结构体,然鹅我发现我学习了一些知识之后,并没有很好地掌握,于是乎,打算写一篇文章来巩固已学知识,并在文末总结学校作业里的写错的题目。(晚上还要苦苦复习高数和线代)

什么是结构?结构是一些值的集合。每个成员可以是不同类型的变量(数组是相同类型的集合)。

代码语言:javascript
复制
struct tag
{
   member-list;
}variable-list;

结构体类型的定义

写法1: 

代码语言:javascript
复制
struct Stu
{
	//学生的属性(成员列表)
	char name[20];
	int age;
};//无变量列表也可以

建立一个类型。

写法2:

代码语言:javascript
复制
struct Stu
{
	//学生的属性(成员列表)
	char name[20];
	int age;
}s1,s2;//无变量列表也可以

s1和s2利用上面的结构体类型,创建一个结构体变量,是struct Stu类型的变量(此时是结构体的全局变量)。

代码语言:javascript
复制
int main()
{
Struct Stu s3;
return 0;
}

此时是局部变量。

一些特殊的声明 

匿名结构体类型

代码语言:javascript
复制
struct 
{
	char name[20];
	int age;
}s1;

匿名结构体类型用一次就不能用了。

代码语言:javascript
复制
struct Node
{
	int data;//定义一个节点的时候,既能够包含一个数值,又能找到下一个节点
	struct Node *next;
};
代码语言:javascript
复制
struct
{
 int a;
 char b;
 float c;
}x;
struct
{
 int a;
 char b;
 float c;
}a[20], *p;
int main()
{
 p=&x;
 return 0;
}

当两个匿名结构体变量相同时, 我们把x的地址放在p里。此时编译器会报警告:从*到*的类型不兼容。

在数据结构中有一个链表的概念,链表中有顺序表。我们只需要让每一节点包含下一个节点,就能使每一个节点找到下一个节点。

代码语言:javascript
复制
struct Node
{
	int data;//定义一个节点的时候,既能够包含一个数值,又能找到下一个节点
	struct Node next;
};//但是这个结构体的字节无法计算,我们无法直接求出它的大小
int main()
{
	return 0;
}

但我们可以选择把下一个节点的地址给上一个节点,这样也可以使不同节点串起来。此时,一个节点被分为两个部分,一个部分存放数值,被称为数值域,另一个部分存放地址,被称为指针域。

代码语言:javascript
复制
struct Point
{
	int x;
    int y;
}p1 = { 3,2 };

struct score
{
	int n;
	char ch;
};

struct Stu
{
	char name[20];
	int age;
	char score s;
};
int main()
{
	struct Point p2 = { 3,4 };
	struct Stu s1 = { "zhangsan",20,{100,'q'}};
    printf("%s %d %d %c",s1.name,s1.age,s1.s.n,s1.s.ch);
}

 这样程序就可以打印了。

结构体内存对齐

这部分内容学校的书上甚至提都没有提,但是不妨碍我们要好好掌握。

代码语言:javascript
复制
struct S1
{
	char c1;
	int i;
	char c2;
};

int main()
{
	printf("%d\n", sizeof(struct s1));
	return 0;
}

计算s1所占字节数,我们可能会下意识认为:char占1个字节,int占8个字节,所以一共占10个字节。But totally wrong!结果是12。出现这个结果的原因是什么呢?

接下来我们介绍结构体对齐的情况:

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

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

   对齐数 = 编译器默认的⼀个对⻬数 与 该成员变量大小的较小值。

- VS 中默认的值为 8 -

Linux中 gcc 没有默认对齐数,对齐数就是成员⾃⾝的大小

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

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

什么是偏移量? 

第一个位置相对于起始位置的偏移量为0,第二个位置为1,以此类推。 

以struct1为例,演示其在内存中的存储过程。首先,char的内存数为1,与vs编译器默认8,取较小值为1,同理int类型为4,char类型为1。c1先在内存中占偏移量为0的位置,再看i,i需要在偏移量为4的位置占4个字节,但目前其偏移量为1,所以需要浪费3个字节。接着i在偏移量为4的位置占4的字节,此时c2的偏移量也为1,无论如何,都满足偏移量为1,所以接着向下存。但是此时为9,并不是正确答案,这是为什么呢?再看第三条规则:结构体总大小为最大对齐数(结构体中每个成员变量都有⼀个对齐数,所有对⻬数中最⼤的)的 整数倍。此时,三个对齐数分别为1,1,4.。 最大对齐数为4,其整数倍为12。所以,我们还需要浪费3个字节。

如果我们想看我们分析的结果是否正确?如何做呢。

我们可以使用这个函数,来计算其所占内存空间。 

代码语言:javascript
复制
#include<stddef.h>
struct S1
{
	char c1;
	int i;
	char c2;
};

int main()
{
printf("%d\n", sizeof(struct s1,c1));
printf("%d\n", sizeof(struct s1,i));
printf("%d\n", sizeof(struct s1,c2));

	return 0;
}

结果为0,4,8。

struct2为8。这也就表明,让占用空间的成员放在一起,会减小内存。

当s3放在s4内部,结果会是什么样呢?我们来看第四条规则: 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结(含嵌套结构体中成员的对⻬数)的整数倍。s3中最大对齐数为8。

这样就可以计算出此结构体的内存数为32。

内存对齐存在的原因

1移植原因。

2数据结构应尽可能在自然边界对齐。

如果像左侧一样,不存在空间浪费地存放。编译器每次读取4个字节,像左侧还要读取两次才能读取到i,如果像右侧,只需要读取一次,中间必须浪费一些空间,得到效率上提升。 

修改默认对齐数

#pragma pack(8)//设置默认对齐数为8

#pragma pack()//取消默认对齐数,还原为默认

结构体传参

代码语言:javascript
复制
struct S
{
 int data[1000];
 int num;
};

void print1(struct S ss)
{
 int i=0;
 for(i=0;i<3,i++)
 {
     printf("%d",ss.data[i]);
 }
 printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S *ps)
{
 int i=0;
 for(i=0;i<3;i++)
 {
 printf("%d\n", ps->data[i]);
 }
}
int main()
{
struct S s = {{1,2,3}, 1000};
//结构体传参
 print1(s); //传结构体
 print2(&s); //传地址
 return 0;
}

print1(s)为传值调用,print2(&2)为传址调用。 一个地址的大小为4或8字节,效果更好。如果print1(s)传地址过去给ss,ss是不会影响s的,ps可能误操作s,这种实现方式不够安全。在struct S*p2前加上const就可以避免这种情况。函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。 如果传递⼀个结构体对象的时候,结构体过⼤,参数压栈的的系统开销⽐较⼤,所以会导致性能的下 降。使用指针的时候,这种情况就不会出现。

结论: 结构体传参的时候,要传结构体的地址。

以上就是结构体的全部内容,欢迎交流!2024快来了,新的一年也要加油呀。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 结构体类型的定义
  • 一些特殊的声明 
    • 匿名结构体类型
    • 结构体内存对齐
    • 内存对齐存在的原因
    • 修改默认对齐数
    • 结构体传参
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档