C进阶-自定义类型:结构体、枚举、联合

本章重点:

结构体:

结构体类型的声明
结构的自引用
结构体变量的定义和初始化
结构体内存对齐
结构体传参
结构体实现位段(位段的填充&可移植性)

 1 结构体的声明

 1.1 结构的基础知识

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

数组:一组相同类型元素的集合

1.2 结构的声明
// struct tag
// {
//     member-list;
// }variable-list;  //变量列表struct Stu
{int age;char name[20];char id[20];
};
struct Stu s1,s2,s3;
1.3 特殊的声明 

在声明结构的时候吗可以不完全声明

//特殊声明
struct 
{int a;char c;float f;
} x;struct 
{int a;char c;float f;
}* p;int main()
{//p = &x; //errreturn 0;
}
1.4 结构体的自引用

 数据结构:描述的是数据在内存中的组织结构

线性数据结构: 假设要存储:1,2,3,4,5      顺序表

 

// struct Node
// {
//     int data;
//     struct Node* next;
// };// typedef struct   //err
// {
//     int data;
//     Node* next;
// } Node;typedef struct Node
{int data;struct Node* next;
} Node;int main()
{Node n = {0};return 0;
}
1.5 结构体变量的定义和初始化 
struct SN
{//char c[20];char c;int i;
}sn1 = {'q',100},sn2 = {.i=50,.c='w'};   //全局变量struct S
{double d;struct SN sn;int arr[10];
};int main()
{//struct SN sn3,sn4;  //局部变量//printf("%c %d\n",sn2.c,sn2.i);//printf("%c %d\n",sn1.c,sn1.i);struct S s = {3.14,{'a',99},{1,2,3,4}};printf("%lf %c %d\n",s.d,s.sn.c,s.sn.i);int i = 0;for (i = 0; i< 10;i++){printf("%d ",s.arr[i]);}return 0;
}
 1.6 结构体内存对齐

结构体内存对齐的规则:

1.结构体的第一个成员永远放在相较于结构体变量起始位置的偏移量为0的位置

2.从第二个成员开始,往后的每个成员都要对齐到某个对齐数的整数倍处。

对齐数:结构体成员自身的大小和默认对齐数的较小值

VS上默认对齐数是8

gcc 没有默认对齐数,对齐数就是结构体成员的自身大小。

3.结构体的总大小,必须上最大对齐数的整数倍

最大对齐数是:是所有成员的对齐数中的最大值

// struct S1
// {
//     char c1;
//     int i;
//     char c2;
// };// struct S2
// {
//     int i;
//     char c1;
//     char c2;
// };// int main()
// {
//     printf("%d\n",sizeof(struct S1)); //12
//     printf("%d\n",sizeof(struct S2));// 8
//     printf("%d\n",offsetof(struct S1,c1));//可以计算结构体成员相较于结构体起始位置的偏移量 //0
//     printf("%d\n",offsetof(struct S1,i));//4
//     printf("%d\n",offsetof(struct S1,c2));//8
//     printf("%d\n",offsetof(struct S2,i));//可以计算结构体成员相较于结构体起始位置的偏移量 //0
//     printf("%d\n",offsetof(struct S2,c1));//4
//     printf("%d\n",offsetof(struct S2,c2));//8
//     //通过上面的现象分析,我们发现结构成员不是按照顺序在内存中连续存放的,而是有一定的对齐规则的
//     return 0;
// }struct S3
{double d;char c;int i;
};struct S4
{char c1;struct S3 s3;double d;
};int main()
{printf("%d\n",sizeof(struct S4)); //32return 0;
}

 为什么存在内存对齐?

1.    平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2.    性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

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

 1.7 修改默认对齐数
#pragma pack(1)
struct S
{char c1;// 1 1 1int a;// 4 1 1char c2;// 1 1 1
};
#pragma pack(1)int main()
{printf("%d\n",sizeof(struct S));return 0;
}
 1.8 结构体传参
struct S
{int data[100];int num;
};void print1(struct S tmp)
{printf("%d\n",tmp.num);
}//优先使用结构体传参
void print2(struct S* ps)
{printf("%d\n",ps->num);
}int main()
{struct S s = {{1,2,3},100};print1(s);print2(&s);return 0;
}

2. 位段 

2.1 什么是位段

位段的声明和结构是类似的,有两个不同:

1.    位段的成员必须是 int、unsigned int 或signed int。

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

struct A
{int _a : 2; //二进制位int _b : 5;int _c : 10;int _d : 30;};int main()
{printf("%d\n",sizeof(struct A));return 0;
}
 2.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;
};int main()
{struct S s = {0};s.a = 10;s.b = 12;s.c = 3;s.d = 4;printf("%d\n",sizeof(struct S));return 0;
}
 2.3 位段的跨平台问题

1.    int 位段被当成有符号数还是无符号数是不确定的。

2.    位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。

3.    位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

4.    当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

枚举:

枚举顾名思义就是一一列举。 把可能的取值一一列举

枚举类型的定义

枚举的优点

枚举的使用

3.1 枚举类型的定义 
enum Color
{RED,GREEN = 8,BLUE
};int main()
{enum Color c = GREEN;printf("%d\n",RED);printf("%d\n",GREEN);printf("%d\n",BLUE);return 0;
}
 3.2 枚举的优点

1.    增加代码的可读性和可维护性

2.    和#define定义的标识符比较枚举有类型检查,更加严谨。

3.    防止了命名污染(封装)

4.    便于调试

5.    使用方便,一次可以定义多个常量

3.3 枚举的使用 
enum Color
{RED = 1,GREEN = 8,BLUE = 4
};int main()
{// enum Color c = GREEN;// printf("%d\n",RED);// printf("%d\n",GREEN);// printf("%d\n",BLUE);enum Color clr = GREEN;clr = 5;return 0;
}

联合:

联合类型的定义

联合的特点

联合大小的计算

 4.1 联合类型的定义

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。

 

union Un
{char c;int i;
};int main()
{printf("%d\n",sizeof(union Un));union Un un = {0};printf("%p\n",&un);printf("%p\n",&un.i);printf("%p\n",&un.c);return 0;
}
 4.2 联合的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。 

union Un
{char c;int i;
};int main()
{printf("%d\n",sizeof(union Un));union Un un = {0};un.i = 0x11223344;un.c = 0x55;printf("%x\n", un.i);// printf("%p\n",&un);// printf("%p\n",&un.i);// printf("%p\n",&un.c);return 0;
}
 4.3 联合的计算
// union Un
// {
//     int i;
//     char c;
// };// int main()
// {
//     printf("%d\n",sizeof(union Un));  //4//     return 0;
// }// int check_sys()
// {
//     union 
//     {
//         int i;
//         char c;
//     } un = {.i = 1};//     return un.c;// }// int main()
// {
//     int ret = check_sys();
//     if(ret ==1)
//     {
//         printf("小端\n");
//     }
//     else
//     {
//         printf("大端\n");
//     }//     return 0;
// }union Un1
{char c[5]; //5 1 8 1int i; //4 8 4
};union Un2
{short c[7]; //14 2 8 2int i; //4 4 8 4
};int main()
{printf("%d\n",sizeof(union Un1)); //5 + 3 = 8printf("%d\n",sizeof(union Un2)); //14 + 2 = 16return 0;
}

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

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

相关文章

【WSN】模拟无线传感器网络研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

配置mysql+Navicat+XShell宝塔:Mark

Centos7开放3306端口&#xff08;iptables 防火墙 未设置&#xff09; Centos7开放3306端口_centos开启3306端口-CSDN博客 firewall-cmd --zonepublic --add-port3306/tcp --permanent Navicat连接1130错误的解决方法 Navicat连接1130错误的解决方法 - 风纳云 ERROR 1062 …

JVM 虚拟机面试知识脑图 初高级

导图下载地址 https://mm.edrawsoft.cn/mobile-share/index.html?uuid3f88d904374599-src&share_type1 类加载器 双亲委派模型 当一个类收到类加载请求,它首先把类加载请求交给父类(如果还有父类,继续往上递交请求).如果父类无法加载该类,再交给子类加载 防止内存中出现…

vivado FFT IP仿真(3)FFT IP选项说明

xilinx FFT IP手册PG109 1 Configuration 2 Implementation 3 Detailed Implementation IP Symbol

Malformed \uxxxx encoding.问题解决方案

问题背景 Maven项目构建时报错如下&#xff0c; [ERROR] Malformed \uxxxx encoding. [ERROR] java.lang.IllegalArgumentException: Malformed \uxxxx encoding. [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re…

IDEA使用模板创建webapp时,web.xml文件版本过低的一种解决方法

创建完成后的web.xml 文件&#xff0c;版本太低 <!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Appl…

使用IntelliJ Idea必备的插件!

趁手的工具让开发事半功倍&#xff0c;好用的IDEA插件让效率加倍。 今天给大家分享几个优秀的IDEA插件。 插件安装 首先得知道在IDEA哪安装插件&#xff1f; 点击File---->Settings---->找到Plugins标签&#xff0c;即可搜索想要的插件进行安装了。 现在来看下有哪些值…

Ubuntu16.04apt更新失败

先设置网络设置 换成nat、桥接&#xff0c;如果发现都不行&#xff0c;那么就继续下面操作 1.如果出现一开始就e&#xff0c;检查源&#xff0c;先换源 2.换完源成功之后&#xff0c;ping网络&#xff0c;如果ping不通就是网络问题 如果ping baidu.com ping不通但是ping 112…

Go流程控制与快乐路径原则

Go流程控制与快乐路径原则 文章目录 Go流程控制与快乐路径原则一、流程控制基本介绍二、if 语句2.1 if 语句介绍2.2 单分支结构的 if 语句形式2.3 Go 的 if 语句的特点2.3.1 分支代码块左大括号与if同行2.3.2 条件表达式不需要括号 三、操作符3.1 逻辑操作符3.2 操作符的优先级…

面试经典 150 题 20 —(数组 / 字符串)— 151. 反转字符串中的单词

151. 反转字符串中的单词 方法一 class Solution { public:string reverseWords(string s) {istringstream instr(s);vector<string> words{};string word;while(instr>>word){words.push_back(word);}int length words.size();string result words[length-1];f…

振弦传感器和振弦采集仪应用隧道安全监测的解决方案

振弦传感器和振弦采集仪应用隧道安全监测的解决方案 现代隧道越来越复杂&#xff0c;对于隧道安全的监测也变得越来越重要。振弦传感器和振弦采集仪已经成为了一种广泛应用的技术&#xff0c;用于隧道结构的监测和评估。它们可以提供更精确的测量结果&#xff0c;并且可以在实…

Android Termux安装MySQL,并使用cpolar实现公网安全远程连接[内网穿透]

文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备&#xff0c;尽管最初并非设计为服务器&#xff0c;但是随着技术的进步我们可以将Android配置为生产力工具&#xff0c;变成一个随身…

微服务10-Sentinel中的隔离和降级

文章目录 降级和隔离1.Feign整合Sentinel来完成降级1.2总结 2.线程隔离两种实现方式的区别3.线程隔离中的舱壁模式3.2总结 4.熔断降级5.熔断策略&#xff08;根据异常比例或者异常数&#xff09; 回顾 我们的限流——>目的&#xff1a;在并发请求的情况下服务出现故障&…

吸烟检测Y8N,支持C++,PYTHON,ANDROID

吸烟检测Y8N&#xff0c;支持C,PYTHON,ANDROID 现在&#xff0c;深度学习已经非常流行&#xff0c;最新出来的YOLOV8&#xff0c;更是将精度和速度达到极限。训练一个目标很简单&#xff0c;首先&#xff0c;标记图片&#xff1b;然后训练得到PT模型&#xff1b;最后转换成ONNX…

抖音小店创业攻略,快速了解这些适合新手经营的类目

抖音小店是抖音平台上的一种新型电商形态&#xff0c;它允许用户在抖音上开设自己的小店&#xff0c;销售自己的商品。抖音小店的开设门槛低&#xff0c;成本也不高&#xff0c;因此很受新手创业者的青睐。那么&#xff0c;下面不若与众将介绍抖音小店中有哪些适合新手创业者经…

hive 知识总结

​编辑 社区公告教程下载分享问答JD 登 录 注册 01 hive 介绍与安装 1 hive介绍与原理分析 Hive是一个基于Hadoop的开源数据仓库工具&#xff0c;用于存储和处理海量结构化数据。它是Facebook 2008年8月开源的一个数据仓库框架&#xff0c;提供了类似于SQL语法的HQL&#xf…

jmeter 请求发送加密参数

最近在做http加密接口&#xff0c;请求头的uid参数及body的请求json参数都经过加密再发送请求&#xff0c;加密方式为&#xff1a;ase256。所以&#xff0c;jmeter发送请求前也需要对uid及json参数进行加密。我这里是让开发写了个加密、解密的jar&#xff0c;jmeter直接调用这个…

掌握 Web3 的关键工具:9大宝藏APP助你玩转区块链

Web3世界充满了无限机遇&#xff0c;但要掌握它&#xff0c;您需要合适的工具&#xfffd;&#xfffd;&#xfffd;。今天&#xff0c;我将为您介绍9款Web3必备APP&#xff0c;涵盖钱包、DEX、和工具三大类别。而且&#xff0c;我要特别强烈推荐一个强大的钱包——Bitget Wall…

初识Java 13-2 异常

目录 标准Java异常 新特性&#xff1a;更好的NullPointerException报告机制 使用finally执行清理 finally有什么用 在return时使用finally 缺陷&#xff1a;异常丢失 异常的约束 构造器 本笔记参考自&#xff1a; 《On Java 中文版》 标准Java异常 Throwable类描述了任…

面试经典 150 题 2 —(滑动窗口)— 3. 无重复字符的最长子串

3. 无重复字符的最长子串 方法 class Solution { public:int lengthOfLongestSubstring(string s) {int result 0, length s.length();int start 0, end 0;while(end < length){// 发现有重复字符时&#xff0c;可以直接把左指针移动到第一个重复字符的下一个位置for(i…