当前位置: 首页 > news >正文

C语言--结构体(Struct)

结构体类型

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
就是一些不同类型的数据结构(结合)在一起,变成结构体。
结构在一起的数据是一起出现,一起消失的,就像是一个类型一样,因为他们是一体的。

struct Stu    //结构体变量名
{int S;    //成员列表char t;
}u4,u5,u6;    //变量列表  ---> 表示是全局变量 “;”不能省略int main()
{struct Stu u1;//创建 结构体类型struct Stu u2;struct Stu u3;  //局部变量return 0;
}

对于此结构体变量,参考下面理解
在这里插入图片描述

结构体变量的创建,初始化,使用

#include <stdio.h>struct Stu   //声明
{char name[20];   int age;int id[10];
};   int main()
{struct Stu s1 = {"changsan",20,2025111401};                           //顺序初始化struct Stu s2 = { .age = 18,.id = 2025111402,.name = "lisi" };        //随机初始化:  '.' + '初始化的成员变量名' = 内容struct Stu s3 = { .age = 18,.age=20,.age=200};                 //随机初始化时,or顺序初始化后,还重新初始化成员变量,默认取最后初始化的值printf("名字:%s 年龄:%d \n", s1.name,s1.age);printf("%d ", s3.age);//  使用 -> 变量名 + '.' + 成员变量名   return 0;
}//输出结果:
//名字:changsan 年龄:20
//200
//

如上,是结构体变量的创建+初始化+使用。

结构的特殊声明

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

struct Stu
{char name[20];int age;int id[10];
}s1;struct
{char name[20];int age;int id[10];
}s2;

s2这种声明结构体变量叫匿名结构体。这种结构体变量,只能使用他的全局变量的形式,无法创建他的局部变量。。。如:

#include <stdio.h>struct
{char name[20];int age;int id[10];
}s2;int main()
{s2.age = 10;for (int i = 0;i < 5;i++){s2.age++;s2.age++;}printf("%d ", s2.age);  //只能创建该结构体变量的全局return 0;
}//输出结果:
//20

这样只能在声明的时候创建该结构体的全局变量(可以是多个全局变量,但只能一次性全部创建),在后续过程中无法再创建。。。

结构体的自引用 X

在结构中包含一个类型为该结构本身的成员是否可以呢?
比如,定义一个链表(雏形):

struct Node
{int data;struct Node n;
};

上述代码正确吗?如果正确,那sizeof(struct Node) 是多少?
仔细分析,其实是不行的,因为一个结构体中再包含一个同类型的结构体变量,这样结构体变量的大小就会无穷的大,是不合理的。
正确的自引用方式:

struct Node
{int data;struct Node* next;
};

存放下一个节点(结构体)的地址,指针大小能确定(4/8字节)。

结构体的重命令

在结构体自引用使用的过程中,可以用 typedef 对匿名结构体类型重命名。

typedef struct Node
{int data;struct Node* next;    //不能写成Node* next ,因为还没重命令完成,不能使用
}Node;

注:因为Node是对前面的匿名结构体类型的重命名产生的,但是在匿名结构体内部提前使用Node类型来创建成员变量,这是不行的。

重命令后,无法创建全局变量,只能创建不同的名称。如:

#include <stdio.h>typedef struct Node
{int data;struct Node* next;    //不能写成Node* next ,因为还没重命令完成,不能使用
}Node ,s1 ,s2;int main()
{Node s;s.data = 100;s1 ss;ss.data = 200;s2 sss;sss.data = 300;printf("%d ", s.data);printf("%d ", ss.data);printf("%d ", sss.data);return 0;
}//输出结果:
//100 200 300

那还这么使用全局变量?只能用常规创建全局变量的方式创建相对应的全局变量:

#include <stdio.h>typedef struct Node
{int data;struct Node* next; 
}Node, s1, s2;Node s;int main()
{s.data = 100;printf("%d ", s.data);return 0;
}//输出结果:
//100

注:创建全局变量时,顺序不能搞错,先声明->再创建。。。

结构体内存对齐

我们已经掌握了结构体的基本使用了。
现在我们深入讨论一个问题:计算结构体的大小。
这也是一个特别热门的考点: 结构体内存对齐

对齐规则

首先得掌握结构体的对齐规则:

  1. 结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处
  1. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    (上一个变量最后的存储位置的下一个地址开始)
    对齐数 = 编译器默认的一个对齐数 与 该成员变量大小的较小值
  1. 结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍
  1. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处
    结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

对于下面这段结构体为例:

#include <stdio.h>struct S1
{char C1;  //1char C2;  //1int n;    //4
};struct S2
{char C1;  //1int n;    //4char C2;  //1
};struct S3
{char C1;struct S1 arr;int n;
};struct S4
{char C1;char C2;
};int main()
{printf("%zd\n", sizeof(struct S1));printf("%zd\n", sizeof(struct S2));printf("%zd\n", sizeof(struct S3));printf("%zd\n", sizeof(struct S4));return 0;
}//输出结果:
//8
//12
//16
//2

在这里插入图片描述
在这里插入图片描述
没用上的空间呢?浪费了,不用了。

为什么存在内存对齐?

大部分的参考资料都是这样说的:

  1. 平台原因 (移植原因):
    不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  1. 性能原因:
    数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。假设一个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

总体来说:结构体的内存对齐是拿空间来换取时间的做法

个人理解:

数据是由谁处理?CPU!
我们知道CPU的“笨宝宝”,你给他两个数据,再给他一个加法符号,他会自动相加!
你给他两个数据,再给他一个减号,他却不认识,就报错了(前面的博客中的例子),那么这个时候给他两个数据,一个数据是负数,再给他一个加号,他就认识了,就能计算了(操作符中提到过)。

跟这个类似,CPU是一个“笨宝宝”,他没有判断能力,只有超强的计算能力。现在你给他一个地址(struct的地址),然后告诉他查第一个数据,这个数据是char类型,那么CPU会根据char类型的大小偏移的方式查这个数据(不偏移的话他肯定越界访问,系统会给他警告),他查到之后自己记住这段数据的最后一个字节的地址,把该段内的内容发给你。
你要第二个数据(int类型)的时候,他根据struct的地址一个一个偏移,直到越过上端他记住过的地址,直接把内容发送给你,再记住最后一个字节的地址,于此类推。。。

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起
比如 小 -> 大 or 大 -> 小来 设计。

修改默认对齐数

那么这么修改默认对其数呢?

#include <stdio.h>#pragma pack(1)  //修改默认对其数(1)
struct S1
{char C1;  //1char C2;  //1int n;    //4
};
#pragma pack()//恢复默认对齐数struct S2
{char C1;  //1char C2;  //1int n;    //4
};int main()
{printf("%zd\n", sizeof(struct S1));printf("%zd\n", sizeof(struct S2));return 0;
}//输出结果:
//6
//8

这样 S1 和S2 类型的成员一模一样,但是S1 和S2 所占空间的大小有了一些区别。

#pragma 这个预处理指令,可以改变编译器的默认对齐数。
结构体在对齐方式不合适的时候,我们可以自己更改
(不乱改,尽量不使用3/7/11等数字)

结构体传参

注:用指针的时候,“.” 会升级成 “->” 。

#include <stdio.h>struct S
{int data[10];int num;
};void Print_1(struct S s1)
{int c = sizeof(s1.data)/sizeof(s1.data[0]);for (int i = 0;i < c;i++){printf("%d ", s1.data[i]);}printf("\n");printf("%d \n", s1.num);s1.num = 9999999;
}void Print_2(struct S* s1)//用地址指向时,用      ->( 可以抽象的理解为  指向的内容 偏移到 后面变量的位置)
{int c = sizeof(s1->data) / sizeof(s1->data[0]);for (int i = 0;i < c;i++){printf("%d ", s1->data[i]);}printf("\n");printf("%d \n", s1->num);
}int main()
{struct S s1 = { {0,1,2,3,4},200 };Print_1(s1);printf("------\n");Print_2(&s1);return 0;
}//输出结果:
//0 1 2 3 4 0 0 0 0 0
//200
//------
//0 1 2 3 4 0 0 0 0 0
//200

上面的print1 和print2 函数哪个好些?首选print2函数。

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

即:传结构体变量本身的时候,要自己创建变量,时间和空间上都有开销。
传指针的时候,可以直接使用(还能修改内容),可以节省时间和空间。

结论:
结构体传参的时候,要传结构体的地址
注:用指针的时候,“.” 会升级成 “->” 。
注:s1.data 的本质是数组,看成数组data正常使用即可 ,其他数据类型也一样。

http://www.dtcms.com/a/611687.html

相关文章:

  • 网站建设忄金手指专业简单aspx网站开发
  • wordpress 导航网站模板设计新颖的网站建站
  • 一起做网店一样的网站北京建设高端网站
  • openEuler 22.03 ARM64 KVM虚拟化安装
  • 西安知名的网站建设公司wordpress登录失败
  • 如何在会议决策错误后进行纠正与说明
  • 哪个网站免费h5模板多网络推广外包注意哪些
  • 网站的布局怎么做采集文章留在网站
  • 淘宝做导航网站织梦网站搬家教程
  • 男人直接做的视频网站注册网站会不会有问题
  • 在那个网站做直播好赚钱吗企业网站seo模板
  • 无锡网站建设开发外贸自建站类型
  • 晋江网站建设联系电话天眼查网站建设公司
  • 什么网站都有漏洞电脑上安装wordpress
  • 宁波网站搭建公司定制企业营销推广
  • ISTJ+RCI_突然的想法-称之为灵感
  • 手机做网站用什么软件吐鲁番高端网站建设平台
  • Java 黑马程序员学习笔记(进阶篇26)
  • 网站开发的进度怎么写网站开发里程碑
  • Xshell终端连接Ubuntu/Debian无颜色的解决方案
  • 国外推广网站有哪些网页设计介绍北京网站
  • 贵港网站建设兼职企业做网站需要什么
  • 怎样在网站做转向连接网站建设素材模板下载
  • 音乐网站建站如何做视频网站
  • 广东宇晟建设工程有限公司网站注册公司取名推荐
  • 网站开发遵循的标准或规范陕西政务服务网
  • 平板电脑可以做网站不张家港网站网络公司
  • docker中安装conda环境
  • 网站模块顺序调整云服务器服务安全
  • 网站开发和网页上传的说法用vscode做网站