C语言,自定义数据类型

news2024/9/22 9:33:28

引言:

C语言当中除了,自己带的基本数据类型,还有一些自定义数据类型,用户自己可以控制数据类型大小,所包含的元素,使用起来更加方便,快捷。

一  数组arr:

对于数组而言,常常记住以下两点: 

1.一定是相同类型元素的数据集合

2.数组只是指数据元素,并不是指只是指是整数;

2.对于数组而言,在内存上是连续分布的

数组的大小等于数据元素类型本本身大小乘以元素个数

二结构体:

2.1结构体介绍:

C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。

结构体中的数据成员可以是基本数据类型(如 int、float、char 等),也可以是其他结构体类型、指针类型等。

2.1.2结构体组成:

结构体定义由关键字 struct 和结构体名组成,结构体名可以根据需要自行定义。

struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

struct tag {
    member-list
    member-list
    member-list//成员列表  
    ...
} variable-list ;//结构体变量
//tag 结构体标签

tag 是结构体标签。

member-list :是标准的变量定义,比如 int i; 或者 float f;,或者其他有效的变量定义。

variable-list :结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。下面是声明 Book 结构的方式:

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;  

在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个。

2.2结构体内存对齐原则:

对于结构体而言,我们需要计算一个结构体内存的时候,需要注意,结构体内存对齐的原则

2.2.1对齐原则:

第一条: 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处;
第二条: 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处;
对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。
VS 中默认的值为 8
- Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩。
第三条: 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的 整数倍;
第四条:如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍;

对于以上数据原则,要熟记。

可以结合以下实例逐条分析:

2.2.2示例计算:

示例一:
struct S1
{
 char c1;
 int i;
 char c2;
};
printf("%d\n", sizeof(struct S1));

注意:首先,结构体也是连续存放的空间,但是存在一定的空间浪费,所以要注意结构体成员的列出,来节省内存空间。

存放c1:

首先了解一下:偏移量,就是指相对于第一个元素存放的起始地址而言的偏移多少的数值。

那么根据第一条原则,我们把第一个成员char 地址(偏移量)设置为0 ,

根据第二条,那么1和8的默认对齐数,选择较小的,那么对应,C1的对齐数就是1

那么我们开始存放的地址就必须是1的倍数,而0是1的倍数。所以存放在第一个位置0。

后面两条是针对于整体和嵌套,暂时不考虑;

存放int  i :

首先,我们刚刚存放第一个元素位置为0,那么开始考虑第二条,存放的位置要是最小对齐数的倍数。那么比较int i和默认对齐数比较,取较小值为对齐数。

那么对于4个字节和8个默认对齐数比较。4小于8,所以对应,我们选择 int i的对齐数为4个字节

那么对于开始存放的第二个地址是从1开始:

而1不是最小对齐数的倍数,所以我们要从它的倍数,4的最小对应倍数是4那么从偏移量为4的地址开始存放。

那么对应的而言,就是说,会有1~3之间3个字节的空间浪费;

存放 char c2:

那么对于char c2 依旧是根据原则,一步一步计算。首先针对于我们的字节。char c2求它的对齐数

char 是1个字节和 8默认对齐数比较,选小的,那么对应就是 1;那么对于内存比较而言,我们存放的地址就要是1的倍数,那么开始存放的地址就是8,8是1的倍数,所以我们可以从8的位置开始存放:

整体内存对齐:

根据第三条原则,结构体的内存大小要是,整体对齐数的倍数。那么整体对齐数就是指结构体所有成员对齐数的较大值, char c1,  int  i,char c2分别对齐数是:1,4,1那么整体对齐数就是4,而目前我们存放使用了9个字节,那么9不是4的倍数,所以还要对齐整体偏移,最近4的倍数是12.

所以整体所占内存大小就是12。

实例二:
#include <stdio.h>
struct s2
{
	char c1;
	char c2;
	int i;
};
int main()
{
	struct s2 test;
	printf("S2结构体大小为:%d\n", sizeof(test));
	return 0;
}

首先 C1作为第一个成员,设置为地址为0的偏移处,c1为一个字节,默认对齐8个字节选择较小的,1作为c1的对齐数。c2起始地址为偏移量1处,c2为1个字节,默认对齐数为8个字节选择较小值为1作为c2的对齐数。1是偏移量1地址的倍数,所以可以存放1个字节。int i为4个字节,默认对齐数为8个字节,选择较小值那么对应为4。开始存放偏移量为3不是4的倍数。所以得从最小公倍数处,即偏移量为4处开始存放 int i。那么整体存放0~7对应整体字节为8个字节,那么开始计算整体对齐数,根据c1,c2,i的对齐数取最大值,即为4。8为4的倍数,所以满足内存对齐原则。

所以整体结构体内存大小为4个字节。

由此S1,S2大小对比可以发现,相同较小元素放一起可以有效节省结构体所占内存大小空间

示例三(结构体嵌套):
struct S3
{
 double d;
 char c;
 int i;
};
printf("%d\n", sizeof(struct S3));
结构体嵌套问题
struct S4
{
 char c1;
 struct S3 s3;
 double d;
};
printf("%d\n", sizeof(struct S4));

计算S3结构体计算方法和上面基本相同,大概看一下我的计算过程:

 

可以计算出大小为16个字节。

计算S4结构体大小:成员c1第一个元素大小为1个字节默认对齐数为1个字节,放置在位置为0处。

计算c1的对齐数,1小于默认对齐数8,所以c1的对齐数为1。开始计算成员2,也就是S3那么S3对齐数,取决于该结构体内最大对齐数,也就是对应8作为该结构体的对齐数。那么对于8,所以要求起始地址就是要求是对齐数倍数处。而成员2的起始偏移量为1,那么对应应该从地址8处开始存放16个字节。也就是存放到8~23。对应成员3 double d,大小为8个字节,默认对齐数8,选择较小值8

那么d开始存放位置要是8的倍数。那么对应成员3开始地址刚好是24为8的倍数开始存放,成员d存放到24~31处。对于整体而言就是0~31整体大小为32。开始计算整体最大对齐数,1,8,8选择最大对齐数8作为对齐数。那么32刚好是8的倍数。所以对应整体大小就是32字节。

2.3结构体“.”和->的区别:

结构体中 “->” 与 “.” 的区别以及使用
两者在同一个代码块内使用的时候其实没有什么太大不同,无非就是声明结构体的时候一个是声明指针,一个是声明结构体。声明结构体的时候分配了内存空间,所以可以用".“直接访问,而声明指针之后并没有分配内存空间,所以用”->“来指向开辟的空间。也可以用”(*buffer).foo" ,等价于"buffer->foo"。

"->"是在声明结构体指针时,访问结构体成员变量时使用。

"."是声明结构体时,访问结构体成员变量时使用。

三 联合体(共用体):

3.1联合体(共用体)介绍:

像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。
但是编译器只会为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间,也就是共用一块空间。所以联合体也叫:共⽤体。 给联合体其中⼀个成员赋值,其他成员的值也跟着变化。

3.2 联合体组成:

为了使用联合体,需要使用 uion关键词来定义联合体。那么对于整体架构其实和结构体差不多:

union [union tag]
{
   member definition;
   member definition;
   ...
   member definition;
} [one or more union variables];

union tag 是可选的,也就是我们声明这个联合体类型叫做声明名字,每个 member definition 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在共用体定义的末尾,最后一个分号之前,您可以指定一个或多个共用体变量,这是可选的。下面定义一个名为 Data 的共用体类型,有三个成员 i、f 和 str:

3.3联合体(共用体)大小计算:

和结构体一样,我们对于共用体计算同样需要根据相应的对齐原则,去计算大小;

3.3.1共用体对齐原则:

联合的⼤⼩⾄少是最⼤成员的⼤⼩。
当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍。

3.4示例计算:

示例一:
union Un
{
 char c;
 int i;
};

计算:第一根据两条原则,计算即可;

 char c 为1个字节  , int i为4个字节计算最大成员大小,最大成员为int 4个字节

那么联合体大小为4个字节,两者对齐数为1 ,4取最大对齐数4。4为4的倍数,所以

整体结构体大小为4个字节。

示例二:
union Un2
{
	short c[7];
	int i;
};

那么对于共用体2而言,它的整体大小,首先成员1为应该数组,那么对于其大小为2*7,大小为14个字节。成员2,int i大小为4个字节。那么取决于较大一位14字节

那么计算共用体对齐,计算,对齐数是取决于其成员的基本数据类型元素大小,而不是整体大小

short是2个字节。那么对于int 4个字节,其对齐数采取4。

那么对于整体共用体大小14不是4的对齐数,所以应该对齐到实际最小公倍数到16个字节。

那么对于两条原则,如果共用体成员只有基本数据类型,不存在自定义数据类型,计算大小往往不需要考虑对齐数,因为对齐数就是基本数据类型元素的字节大小,即使考虑本是上内存大小不受影响

3.5联合体(共用体)简单应用:

可以用来计算所使用内存存储空间到底是大端存储还是小端存储。

知识补充:大小端存储(Endianess)是指多字节数据在计算机内存中的字节排列顺序。具体来说,它决定了数据的高位字节(Most Significant Byte, MSB)和低位字节(Least Significant Byte, LSB)在内存地址中的存放顺序。根据字节的存储顺序,主要可以分为两种类型:

  1. 大端(Big Endian)存储
    • 在大端存储中,高位字节存储在内存的低地址端,低位字节存储在内存的高地址端。
    • 举例来说,一个16位的整数0x1234在大端存储中,其内存表示会是12 34(十六进制),即高位字节12在前,低位字节34在后。
  2. 小端(Little Endian)存储
    • 在小端存储中,低位字节存储在内存的低地址端,高位字节存储在内存的高地址端。
    • 同样以16位整数0x1234为例,在小端存储中,其内存表示会是34 12(十六进制),即低位字节34在前,高位字节12在后。

这两种存储方式对于单个字节的数据没有区别,但对于多字节的数据(如整型、浮点型等)就有明显的不同。在编写跨平台的软件时,需要特别注意数据的字节序,因为不同的硬件平台可能采用不同的字节序。例如,Intel和AMD的x86和x86_64架构通常使用小端存储,而一些网络协议和文件格式(如网络字节序)则采用大端存储。

在实际编程中,有时需要进行字节序的转换,以确保数据在不同平台之间的正确传输和解析。例如,可以使用函数如htonl(host to network long)和ntohl(network to host long)在网络编程中进行32位整数的字节序转换。对于更通用的字节序处理,可以使用联合(union)或者位操作等技巧来进行编程。

int check_sys()
{
 union
 {
 int i;
 char c;
 }un;
 un.i = 1;
 return un.c;//返回1是⼩端,返回0是⼤端
}解读程序

解读:

这里的关键在于理解整数1在内存中的表示。在计算机中,整数1通常表示为0000 0001(对于32位整数)。但是,这个表示如何映射到char类型的un.c取决于系统的字节序。

  • 大端系统上,高位字节(即0000)会存储在内存的低地址端,而un.c(一个char类型)只会读取这个地址的值,所以它会返回0。
  • 小端系统上,低位字节(即0001)会存储在内存的低地址端,所以un.c会返回1。

四 枚举 :

4.1枚举介绍:

枚举顾名思义就是⼀⼀列举,把可能的取值⼀⼀列举。
⽐如我们现实⽣活中:
⼀周的星期⼀到星期⽇是有限的7天,可以⼀⼀列举
性别有:男、⼥、保密,也可以⼀⼀列举
⽉份有12个⽉,也可以⼀⼀列举
三原⾊,也是可以意义列举
这些数据的表⽰就可以使⽤枚举了。
enum Day//星期
{
 Mon,
 Tues,
 Wed,
 Thur,
 Fri,
 Sat,
 Sun
};
enum Sex//性别
{
 MALE,

 FEMALE,
 SECRET
};
enum Color//颜⾊
{
 RED,
 GREEN,
 BLUE
};

简单来说就是一一列举,实际应用非常方便。

4.2枚举赋值计算:

对于枚举的值,实际上枚举的成员都是有值的,对于枚举的值往往声明定义的时候就已经定了。

不能在改变。所以对于我们而言。往往就是一句话枚举常量。

默认枚举成员数值是从0开始依次递增,其次每次递增量为1

示例一:

enum Color//颜⾊
{
 RED,
 GREEN,
 BLUE
};

默认就是从0开始,对于递增量为1。

那么就是 0,1,2;

示例二:

enum Color//颜⾊
{
 RED=1,
 GREEN,
 BLUE
};

RED为1,开始递增,增量为1,那么对应1,2,3 

示例三:

enum Color//颜⾊
{
 RED,
 GREEN=4,
 BLUE
};

RED没有赋值从开始,默认从0,开始递增,GREEN赋值4,开始递增,增量为1 ,那么BLUE开始从4开始递增,增量为1,那么对应5.

所以结果1,4,5。

4.3枚举好处:

1. 增加代码的可读性和可维护性
2. 和#define定义的标识符⽐较枚举有类型检查,更加严谨。
3. 便于调试,预处理阶段会删除 #define 定义的符号
4. 使⽤⽅便,⼀次可以定义多个常量
5. 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤

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

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

相关文章

LeetCod459:重复的子字符串

题目描述 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s “abab” 输出: true 解释: 可由子串 “ab” 重复两次构成。 示例 2: 输入: s “aba” 输出: false 示例 3: 输入: s “abcabcabcabc” 输出: true 解释: 可…

Obsidian插件PicGo-图床创建使用[腾讯云保姆级教程]

一、下载PicGo并配置 1&#xff1a;安装插件 首先插件市场搜索picgo会出现Image auto upload&#xff0c;这个就是PicGo安装此插件并启用即可 2&#xff1a;安装PicGo软件 打开此链接&#xff1a;https://github.com/Molunerfinn/PicGo 自己选择一个方式下载&#xff0c;我…

unicloud 云函数 介绍及使用

普通云函数 callFunction方式云函数&#xff0c;也称之为普通云函数。 uni-app的前端代码&#xff0c;不再执行uni.request联网&#xff0c;而是通过uniCloud.callFunction调用云函数。 callFunction方式避免了服务器提供域名&#xff0c;不暴露固定ip&#xff0c;减少被攻击…

【JS】闭包的漏洞

下面这段代码可以实现&#xff1a;通过立即执行函数o返回对象中的get方法&#xff0c;通过参数key得到fn函数内部对象obj中的值。 var fn function () {var obj {a: 1,b: 2}return {get: function (key) {return obj[key]}} }() console.log(fn.get(b)); // 2这是一个典型的…

3个好用的WP免费主题

免费wordpress模板下载 高端大气上档次的免费wordpress主题&#xff0c;首页大图全屏显示经典风格的wordpress主题。 https://www.wpniu.com/themes/289.html 经典的红色免费wordpress主题 这是一款经典的免费wordpress主题&#xff0c;被广泛应用于多个行业的网站。 https…

智慧公厕的系统构成与功能解析

智慧公厕系统是通过传感器和云平台相结合的创新技术&#xff0c;旨在提供更好的公厕管理与服务。智慧公厕从系统的构成来看&#xff0c;主要分为感知层&#xff08;数据收集&#xff09;、传输层&#xff08;数据传输&#xff09;、平台层&#xff08;数据处理&#xff09;和应…

VUE+Vant实现H5组织架构选人选公司组件

提醒自己&#xff1a; 这是之前的逻辑&#xff0c;或许你重新写会有更好的方法&#xff0c;可以参考逻辑&#xff01;&#xff01;&#xff01; 功能介绍 1.有面包屑点击切换 2.有公司、部门、人员 3.单选、多选实现 4.编辑/回显 5.使用随意切换层级和跳转到指定层级回显等功…

CSAPP | Lab1-Data Lab 详细解析

You may assume that your machine:1. Uses 2s complement, 32-bit representations of integers.2. Performs right shifts arithmetically.3. Has unpredictable behavior when shifting if the shift amountis less than 0 or greater than 31.Part1&#xff1a;整数 1.Bit…

力扣爆刷第102天之hot100五连刷96-100

力扣爆刷第102天之hot100五连刷96-100 文章目录 力扣爆刷第102天之hot100五连刷96-100一、136. 只出现一次的数字二、169. 多数元素三、75. 颜色分类四、31. 下一个排列五、287. 寻找重复数 一、136. 只出现一次的数字 题目链接&#xff1a;https://leetcode.cn/problems/sing…

Java疫苗接种管理系统

本系统lw为2024-3-21本人原创&#xff0c;查chong13% 1.3W字&#xff0c;可以直接上交&#xff0c;这并不是乱七八糟的技术文档和项目文档。 4.2 功能结构设计 可视化的疫苗接种管理系统功能结构设计主要包括以下几个模块&#xff1a; 登录注册模块&#xff1a;这个模块负责…

算法体系-14 第十四 贪心算法(上)

一 、 递归套路解决判断完全二叉树 1.1 描述 1.2 分析 1.2 分析 第二种 第三种 第四种 1.3 代码 public static boolean isCBT2(Node head) {return process(head).isCBT;}public static class Info {public boolean isFull;public boolean isCBT;public int height;public…

hcia静态实验

题目&#xff1a; 要求&#xff1a; 1、R6为isp&#xff0c;接口ip均为公有地址&#xff0c;该设备只能配置ip地址&#xff0c;之后不能再对其进行任何其他配置 2、r1到r5为局域网&#xff0c;私有ip地址为192.168.1.0 24&#xff0c;合理分配 3、r1,r2,r4各有两个环回地址&am…

2024年全国职业院校技能大赛中职组大数据应用与服务赛项题库参考答案陆续更新中,敬请期待…

2024年全国职业院校技能大赛中职组大数据应用与服务赛项题库参考答案陆续更新中&#xff0c;敬请期待… 武汉唯众智创科技有限公司 2024 年 3 月 联系人&#xff1a;辜渝傧13037102709 题号&#xff1a;试题04 ZZ052-大数据应用与服务赛选赛题04 模块一&#xff1a;平台搭建…

JVM面试篇

面试篇就是复习前面学的 什么是JVM 1.定义&#xff1a;JVM指的是Java虚拟机&#xff0c;本质是一个运行在计算机上的程序 2.作用&#xff1a;为了支持Java中Write Once &#xff0c;Run Anywhere 编写一次 到处运行的跨平台特性 功能&#xff1a; 1.解释和运行 2.内存管理…

jconsole的使用

前提 已安装jdk 使用步骤 1、命令行输入jconsole

#Linux(第一个Hello World以及GCC基本用法)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;gcc简介&#xff1a;GCC&#xff08;GNU Compiler Collection&#xff0c;GNU编译器套件&#xff09;是由GNU开发的编程语言编译器。GNU编译…

收割互联网大厂Offer面经

大家好&#xff0c;我是爱编程的喵喵。双985硕士毕业&#xff0c;现担任全栈工程师一职&#xff0c;热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。…

HarmonyOS系统开发ArkTS常用组件文本输入及参数

TextInput文本输入组件&#xff0c;用于接收用户输入的文本内容。 1、TextInput组件的参数 TextInput(value?:{placeholder?: string|Resource , text?: string|Resource}) placeholder属性用于设置无输入时的提示文本text用于设置输入框当前的文本内容 Entry Component st…

Javaweb学习记录(三)请求响应案例

下面为一个请求响应案例&#xff0c;postman发送请求&#xff0c;服务器响应将一个xml文件中的数据通过读取解析&#xff0c;将其用Result类标准的格式返回前端&#xff0c;在前端用json的方式显示 后端Controller代码 1、通过本类的字节码文件得到类加载器并寻找到需要解析的…

最全APP抓包大法

前言&#xff1a;最近工作中遇到一些比较奇葩的App&#xff0c;一边测试一边搜集整理出了比较全的姿势。如有错误之处&#xff0c;还请各位师傅多多指教。 如何判断&#xff1a;连接Fiddler代理–>抓不到包–>关闭Fiddler后正常通信。 解决方法&#xff1a;PC端模拟器如…