C语言---自定义类型(上)(结构体类型)

结构体

        结构体的定义与声明

                结构体其实和数组一样,都是一些值的集合,只不过数组是一系类相同类型的值,而结构体里边的成员可以是不同的数据类型。

                关于它的声明,所用到的关键字是struct。

           声明的语法如下:

           struct 结构体名

          {

                成员变量列表;

           }变量名;

                我先举个例子,就比如一个学生有名字、年龄、成绩等信息。那么此时就可以用结构体来描述它。

struct Stu
{char name[20];//名字int age;double score;
};

        结构体变量的定义和初始化及其访问

                定义

                在刚才创建完成了结构体之后,我们就可以创建结构体的变量了。

                一共有三种方式:下面以代码加注释的方式给出。

struct Stu
{char name[20];//名字int age;double score;
}stu1;//在定义结构体的时候就创建的全局变量struct Stu stu2;//创建的全局结构体变量int main()
{struct Stu stu3;//创建的局部结构体变量return 0;
}

                初始化

             刚才上边的代码已经创建了几个Stu类型的结构体变量,现在我给结构体变量stu3初始化,代码如下

             //

             stu3 = {"xxc",18,99.0};//注意,我们给它初始化的时候需要按照顺序,如果你想要按照自己的顺序去初始化,那就要用到结构体成员访问操作符 ( . )

             stu3 = {.age = 20 , .name = "zhangsan" , .score = 98.5};

                访问结构体变量

                访问结构体的成员变量有两种方式,第一种比较的直接,我们用结构体变量.成员名的方式去访问结构体里的成员。第二种方式就要用到指针了,通过结构体指针->成员名的方式。代码如下:

#include<stdio.h>struct Stu
{char name[20];int age;float score;
};int main()
{//第一种方式打印struct Stu stu = { "zhangsan",21,98.4f };printf("%d %f\n", stu.age, stu.score);//第二种方式打印,先得到结构体的地址,再用指针的方式去打印struct Stu* p = &stu;printf("%d %f\n", p->age, p->score);return 0;
}

        嵌套结构体与匿名结构体类型

                嵌套结构体:

                嵌套结构体,顾名思义就是结构体充当了结构体的成员变量,请看下边的代码(同时,我会将访问其成员变量也附加进去):

//注意:以下的代码只是演示,没有什么实际的含义
#include<stdio.h>
struct id
{char ID[25];int x;
};struct Stu
{char name[20];struct id identity;
};int main()
{struct Stu stu1 = { "zhangsan",{"123456",2} };return 0;
}

                匿名结构体:

                匿名结构体就是结构体在创建的时候没给它名字,如下

struct
{
char name[20];
int age;
};

           这样的话就不能创建结构体的变量了,只能用三种创建方法的第一种来创建,就是在定义的时候直接创建。并且你会发现当你取出他的地址赋值给一个匿名结构体类型的指针变量的时候是会失败的。因为C标准认为它们是两种不同的类型。所以往往匿名结构体类型只能用一次。

        结构体的内存对齐

                每一种数据只要存在在内存当中就肯定有大小,结构体也不例外,接下来所要讨论的就是结构体的内存大小,C语言给出了一套计算它大小的规则,我们称之为结构体的内存对齐。

           对齐规则:

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

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

                3.结构体的总大小为最大对齐数的整数倍

                接下来我们先来解释一下几个名词的含义:

                偏移量:我们可以借助offsetof宏来帮助我们理解,offsetof可以计算出结构体的成员相较于结构体起始位置的偏移量。offsetof有两个参数,第一个参数是结构体变量名字,第二个参数是结构体内部的成员名。  

                由上图我们可以知道每个结构体成员的偏移量是多少,如果你还没有概念,请不要着急,我会把所有名词解释完之后再次回过头来全部解释一下。

                对齐数: 在我们常见的编译器vs里边,默认的对齐数是8,但在计算结构体大小的时候,我们需要将默认的对齐数与该结构体成员变量的大小做比较,取较小的那个作为我们计算大小时候的依据。

                最大对齐数:结构体里边的每一个成员变量都有一个对齐数,它们之中最大的那个就叫做最大对齐数。

                了解了以上的规则与概念之后,我们再将上边截图里边的结构体拿出来,来根据规则计算一下它的大小。

                结构体嵌套结构体的内存对齐

                当我们想要计算的结构体里边有结构体嵌套的时候,它的大小又该如何计算呢?

                这时候,在上边规则的三条规则之下还有一条规则。

           4.当存在嵌套结构体的时候,该结构体成员对齐到自己内部成员的最大对齐数的整数倍处,结构体的大小就是全部成员(包括嵌套结构体的成员)的最大对齐数的整数倍。

                下边来看一个例子:

                修改默认对齐数:

                我们在上边已经提到过了,在vs里边的默认对齐数为8,当我们觉得这个默认对齐数不合适的时候,我们就可以用预处理指令#pragma来修改默认的对齐数。

#include<stdio.h>
#pragma pack(1)//设置默认对齐数为1
struct test
{char c1;char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认对齐数为8的状态。
int main()
{struct test test2;printf("%d\n", sizeof(test2));return 0;
}

        结构体传参

                函数的传参分为两种,一种是传值,一种是传址。下边的代码将结构体的两种传参方式一并演示。

#include<stdio.h>
struct s1
{char a;int b;char c;
};void test1(struct s1 s)
{printf("test1的打印:%d\n", s.b);
}void test2(struct s1* ps)
{printf("test2的打印:%d\n", ps->b);
}int main()
{struct s1 sss;sss.b = 10;test1(sss);test2(&sss);return 0;
}

                这里再补充一个点,利用地址传参可以很好的提升程序的运行效率,因为如果是传值调用的话,程序会在内存里又开辟一块空间来临时拷贝实参。

        结构体实现位段

        首先明确位段在定义时候的两个注意点

        1.位段的成员必须是int,unsigned int,signed int,char,在C99中,位段成员的类型还可以是其他类型

        2.  位段的成员名后边有一个冒号和一个数字。

        如下就是一个基本的位段的定义

struct s
{int a : 2;int b : 4;int c : 6;
};

                位段的内存分配:

                在定义位段的时候,位段的每一个成员的冒号后边的数字代表的是比特位的意思,也就是在定义位段的成员变量的时候,已经把它所占的空间大小也限定住了。

                位段的空间是按照4个字节或者1个字节的大小来开辟空间的。还有一个值得注意的点就是位段不具有移植性,当需要跨平台使用的不推荐使用位段。

                接下来用一个例子来说明位段的内存分配:

                由以上的例子可见,位段的作用本质上还是在节约内存空间的消耗。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88838.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88838.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java观察者模式实现方式与测试方法

一、实现方式 自定义实现 通过手动定义Subject和Observer接口&#xff0c;实现一对多依赖关系&#xff1a; // 观察者接口 public interface Observer {void update(float temp, float humidity, float pressure); } // 主题接口 public interface Subject {void registerObser…

leetGPU解题笔记(1)

1.题面 题目要求 向量加法 实现一个程序&#xff0c;在GPU上对两个包含32位浮点数的向量执行逐元素加法。该程序应接受两个长度相等的输入向量&#xff0c;并生成一个包含它们和的输出向量。 实现要求 禁止使用外部库 solve函数签名必须保持不变 最终结果必须存储在向量C中 示例…

5. JVM 的方法区

1. JVM介绍和运行流程-CSDN博客 2. 什么是程序计数器-CSDN博客 3. java 堆和 JVM 内存结构-CSDN博客 4. 虚拟机栈-CSDN博客 5. JVM 的方法区-CSDN博客 6. JVM直接内存-CSDN博客 7. JVM类加载器与双亲委派模型-CSDN博客 8. JVM类装载的执行过程-CSDN博客 9. JVM垃圾回收…

网络安全的基本练习

一.docker搭建 1.安装dockerapt-get install docker.io docker-compose2.编写配置文件&#xff08;注意路径正确&#xff09;vim /etc/systemd/system/docker.service.d/http-proxy.conf[Service] Environment"HTTP_PROXYhttp://科学上网访问的ip:端口" Environment&…

380. O(1) 时间插入、删除和获取随机元素

实现RandomizedSet 类&#xff1a; RandomizedSet() 初始化 RandomizedSet 对象 bool insert(int val) 当元素 val 不存在时&#xff0c;向集合中插入该项&#xff0c;并返回 true &#xff1b;否则&#xff0c;返回 false 。 bool remove(int val) 当元素 val 存在时&#xff…

【LeetCode Hot100 | 每日刷题】字母异位词分组

题目链接&#xff1a;49. 字母异位词分组 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 示例 1: 输入: strs ["eat", "tea", "tan"…

docker 安装windows

目录 下载地址&#xff1a; 使用教程&#xff1a; docker compose 查看版本 测试启动 hello-world 报错1 The system cannot find the file specified&#xff1a; 检查 Docker Desktop 是否运行中 报错2HF_ENDPOINT 1. 临时解决方案&#xff08;当前终端会话有效&…

docker compose 和build

目录 docker compose 和build 的区别是什么&#xff1f; 核心差别&#xff1a; 1. docker build --platform linux/amd64 -f Dockerfile -t infiniflow/ragflow:nightly_lbg . 2. docker compose -f docker-compose-gpu.yml up -d 二者如何配合&#xff1f; 总结 docker …

裂变时刻:全球关税重构下的券商交易系统跃迁路线图(2025-2027)

——基于RWA清算、量子加密与实时非线性风控的下一代跨境基础设施核心事件锚定&#xff1a;特朗普于7月7日对14国启动分级关税制裁&#xff08;日韩25%、东南亚30%-40%、金砖关联国10%附加税&#xff09;&#xff0c;引发日元兑美元暴跌至144.47、铜价单日跳涨3.2%、散户单日交…

python爬虫初入门——基本库和写入方法

1.准备环境 python环境&#xff1a;3.10 2.常用库 1.请求库&#xff1a;实现 HTTP 请求操作 requests&#xff1a;基于 urllib 编写的&#xff0c;阻塞式 HTTP 请求库&#xff0c;发出一个请求&#xff0c;一直等待服务器响应后&#xff0c;程序才能进行下一步处理。seleni…

Sonar扫描C#代码配置

需要的工具 MSBuild、sonar-scanner-4.6.1.2450-windows、jdk1.8.0_181 下载地址&#xff1a;https://download.csdn.net/download/code12313/91315686 配置sonar的地址 一、环境变量配置 1.新建变量&#xff0c;nameSONAR_RUNNER_MSBUILD_HOME。valueD:\work\dev\dev_serve…

python 在运行时没有加载修改后的版本

陈旧的Python字节码 (.pyc 文件)&#xff1a;最常见的原因&#xff01;Python 会把你修改的 .py 文件编译成 .pyc 字节码来加速后续运行。有时&#xff0c;即使你修改了 .py 文件&#xff0c;系统可能仍然固执地加载旧的、未被删除的 .pyc 文件。1. 用“硬编码探针”强制验证# …

【会员专享数据】2013-2024年我国省市县三级逐年SO₂数值数据(Shp/Excel格式)

之前我们分享过2013-2024年全国范围逐年SO₂栅格数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff01;该数据来源于韦晶博士、李占清教授团队发布在国家青藏高原科学数据中心网站上的中国高分辨率高质量近地表空气污染物数据集。很多小伙伴拿到数据后反馈栅格数据…

出现SSL连接错误的原因和解决方案

介绍 SSL连接错误是一种常见但关键的问题&#xff0c;这可能会阻止客户端和服务器之间的安全连接。这些错误发生在TLS握手过程失败时&#xff0c;这意味着客户端和服务器无法建立安全的HTTPS连接。这种失败可以在SSL/TLS协商过程中的任何阶段发生&#xff0c;从初始协议协议到…

vue3 el-date-picker 保存后 日期减一问题

在使用 el-date-picker&#xff08;Element UI 的日期选择器组件&#xff09;时&#xff0c;如果你发现日期在保存到后台后自动减一&#xff0c;这通常是由于时区差异或者是时间格式解析问题导致的。这里有一些可能的解决方案&#xff1a;1. 检查前端发送的日期格式确保你在前端…

什么是IP关联?跨境卖家如何有效避免IP关联?

一位深圳卖家曾管理30个亚马逊店铺账号&#xff0c;某日清晨发现所有账号被批量封禁——原因竟是平台检测到这些账号长期共享同一IP地址&#xff0c;判定为“IP关联”。而在跨境领域如亚马逊、eBay、Shopee、TikTok等平台&#xff09;&#xff0c;对于IP关联的判定都是比较严格…

Redis集群方案——哨兵机制

Redis Sentinel&#xff08;哨兵&#xff09;是Redis官方提供的高可用性(HA)解决方案&#xff0c;用于管理Redis主从架构并实现自动故障转移。一、集群结构和作用哨兵是一个分布式系统&#xff0c;由多个哨兵节点组成&#xff1a;哨兵的作用如下&#xff1a;监控&#xff1a;Se…

1.2.3_2 TCP/IP模型

在这个视频中&#xff0c;我们要探讨TCP/IP模型。对于TCP/IP模型考试的要求是这样的&#xff0c;首先我们需要记住它各个层次的名称和顺序&#xff0c;以及我们需要了解TCP/IP 模型和OSI参考模型&#xff0c;它们在设计理念上有哪些区别&#xff0c;设计理念的区别又导致了TCP/…

EVOLVEpro安装使用教程-蛋白质语言模型驱动的快速定向进化

写在前面&#xff1a;蛋白质是生命活动的基石&#xff0c;其功能和序列之间的复杂关系长期以来吸引着科学家们的关注。尽管深度突变扫描等实验方法可以解析蛋白质突变的功能影响&#xff0c;但这些技术的应用范围局限于序列空间的一小部分。近年来&#xff0c;基于蛋白质语言模…

【Linux】Rocky Linux 清华镜像源安装 GitLab

使用清华镜像源安装 GitLab 地址&#xff1a;清华镜像源 1. 搜索 gitlab&#xff0c;我们选择 gitlab-ce 社区版进行安装 2. 新建 /etc/yum.repos.d/gitlab-ce.repo&#xff0c;内容为 注意&#xff1a;el$releasever 是清华镜像源内的文件夹版本 [gitlab-ce] nameGitlab C…