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

深入探索C语言自定义类型:打造你的编程世界

一、什么是自定义类型

C语言提供了丰富的内置类型,常见的有int, char, float, double, 以及各种指针。

除此之外,我们还能自己创建一些类型,这些类型称为自定义类型,如数组,结构体,枚举类型和联合体类型。

二、数组

把一组相同类型的元素放到一起,就是数组。数组按照结构分为一维数组,二维数组等等,按照存储元素类型又可以分为整型数组,浮点型数组等等。

2.1 定义

假设一个数组能存储5个元素,每个元素是int类型的,可以如下定义:


int arr[5];

上面是一个常见的一维数组。如果我们想定义一个二维数组呢?比如一个3行5列的数组,每个元素是char*类型,应该如下定义:


char* ch[3][5];

2.2 初始化

对于一维数组,可以用大括号把要初始化的数据括起来,用来初始化这个数组。如:


int arr[5] = {1,2,3,4,5};

对于上面这行代码,可以这么用语言表述:有一个一维数组,数组名叫做arr,数组存储了5个元素,每个元素的类型是int,在定义这个数组的同时我们对它进行了初始化,使得它存储的元素分别是1~5。

以上写法非常基础,还有一些进阶的写法。比如,当数组定义的同时对其初始化,可以省略元素个数。如:


int arr[] = {1,2,3,4,5};

此时编译器会根据大括号里有5个元素,来确定数组的元素个数是5。

如果我们只想初始化一部分元素呢?


int arr[5] = {1,2,3};

数组一共有5个元素,但我们只初始化了3个。当初始化的元素个数小于数组的元素个数时,剩余的元素会被默认初始化成0。如以上的代码的意思是:我们把数组的前3个元素初始化成1,2,3,剩下的2个元素都初始化成0。这种初始化方式被称为不完全初始化

思考:如何创建一个数组,数组名叫ch,能存储10个元素,存储的元素类型是char,并把所有元素都初始化成'\0'(ASCII码值是0)?


char ch[10] = {0};

以上是一维数组的初始化。如果是二维数组呢?假设有一个三行五列的数组,总共有15个数,分别是:

第一行:1,2,3,4,5

第二行:6,7,8,9,10

第三行:11,12,13,14,15

我们可以把每一行当成一个一维数组,用大括号括起来,并且在最外面再加上一个大括号。


int arr[3][5] = {{1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15}};

对于二维数组,如果能确定行数,可以把行数省略。注意:列数无论如何都不能省略


int arr[][5] = {{1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15}};

以上代码中,编译器会自动识别数组一共有3行。

如果确定数组元素的顺序,内层的大括号可以省略。如:


int arr[3][5] = {1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15};

以上代码效果是一样的。编译器会自动用1,2,3,4,5初始化第一行,6,7,8,9,10初始化第二行,依此类推。

如果是不完全初始化,没有初始化的元素会被默认初始化成0。


int arr[3][5] = {1,2,3,4,5, 6,7,8,9,10};

以上代码中,第三行会被默认初始化成0。

注意:如果只定义,不初始化,并且数组是局部的(在大括号内部),则所有的元素都是随机值


int arr[5];

此时数组存储的是5个随机值。

2.3 访问

数组的元素是有下标的,每个元素都对应一个下标。第一个元素的下标是0,后面元素的下标依次递增。如假设一个一维数组有5个元素,则元素的下标分别是0~4。数组的元素可以用下标访问。如:


arr[3] = 30;

就把数组arr中下标为3的元素改成了30。

对于二维数组,每个元素有2个下标。行标和列标都是从0开始的。假设有一个3行5列的数组,则第一行的行标为0,第二行的行标为1,第三行的行标为2。列标同理,第一列到第五列的下标分别是0~4。每个元素都要写明白行标和列标,如:


arr[2][3] = 100;

就表示把数组的行标为2,列标为3的元素改成了100。

2.4 内存分布

对于一维数组,随着下标的增长,地址是连续的,由低到高变化的


char ch[5];
for (int i = 0; i < 5; ++i)
{printf("&ch[%d] = %p\n", i, &ch[i]);
}

打印出来的地址信息是:

可以发现地址是连续增长的,由于一个char类型的数据是1个字节,相邻元素的地址也相差1个字节。

那二维数组呢?


char ch[3][5];
for (int i = 0; i < 3; ++i)
{for (int j = 0; j < 5; ++j){printf("&ch[%d][%d] = %p\n", i, j, &ch[i][j]);}
}

可以看到相同行中,随着列标的增长,地址是由低到高连续增长的。并且每一行的最后一个元素和下一行的第一个元素是无缝对接的。

三、结构体类型

3.1 定义

数组是把相同类型的元素放到一块去。如果是把不同的元素放到一块去呢?比如说,要想描述清楚一个学生,我们需要知道他的姓名,学号和成绩。姓名和学号是字符数组,成绩是浮点型。我们就可以声明一个结构体类型:


struct Stu
{char name[20];char id[20];float score;
};

其中,struct Stu是一种结构体类型,name,id,score就是这个结构体类型创建出来的结构体变量的成员变量

这样,我们就可以定义一个结构体,用来描述某个学生。


struct Stu s;

我们可以在声明的同时定义。如:


struct Stu
{char name[20];char id[20];float score;
}s;

3.2 初始化

如果我们想在定义的同时对这个结构体初始化,可以用大括号把初始化的数据括起来。


struct Stu s = {"Zhang San", "12345xyz", 95.0f};

我们可以在声明的同时初始化:


struct Stu
{char name[20];char id[20];float score;
}s = {"Zhang San", "12345xyz", 95.0f};

3.3 访问

如何把张三的成绩改成59.5f呢?我们可以使用结构成员访问操作符。具体使用方式是:


结构体变量名.成员变量名

如:


s.score = 59.5f;

假设我们使用了一个指针ps来保存s的地址。


struct Stu* ps = &s;

那么访问时就需要先解引用。


(*ps).score = 59.5f;

但这样写太麻烦了,有一种写法和上面这种写法是等价的。


ps->score = 59.5f;

这里的->就等价于先解引用再访问结构体成员变量。

3.4 内存分布

划重点!结构体在内存中的存储需要遵循内存对齐规则。

先介绍几个概念:

  1. 针对某一个地址ptr1,我们定义另一个地址ptr2的偏移量为((int)ptr2-(int)ptr1)。简单来说,某一个地址相对于另一个地址的偏移量就是把这两个地址当成整数后的差。

  2. 每个编译器会根据环境,有一个默认对齐数。这个默认对齐数取决于编译器,但我们是可以修改的。修改方法如下:


#pragma pack(4)

就把默认对齐数设置成4。如果省略括号里的数,就会重置默认对齐数为默认值。


#pragma pack()

内存对齐的规则如下:

  1. 结构体变量的第一个成员变量存储在偏移量为0的地址处。注意:此处的偏移量是针对某一个地址的偏移量,对于同一个结构体变量,我们讨论偏移量都是针对同一个地址的偏移量。

  2. 从第二个成员变量开始,存储位置的偏移量是(自身大小和默认对齐数的较小值)的整数倍。我们把括号括起来的部分称之为这个成员变量的对齐数。把这个结构体变量的所有对齐数的最大值称之为这个结构体变量的最大对齐数

  3. 结构体变量的总大小是这个结构体变量的最大对齐数的整数倍。

  4. 以上三点是针对没有嵌套结构体的情况,也就是说,结构体的成员变量中不存在结构体。对于嵌套的结构体的对齐数的计算也满足规则2,结构体的总大小是所有对齐数(包括嵌套结构体的对齐数)的整数倍。

举个例子:以下程序会输出多少?


#include <stdio.h>#pragma pack(8)
struct A
{double d1;char c1;int i;double d2;char c2;
}a;
#pragma pack()int main()
{printf("%d\n", sizeof(a));return 0;
}

根据规则1,d1的起始偏移量为0,而d1的大小是8,故d1的偏移量是0~7。

根据规则2,c1的起始偏移量至少为8,且是其对齐数的整数倍。c1的对齐数为min(sizeof(c1), 8)=1,8是1的整数倍。又因为c1的大小是1,故c1的偏移量是8。

根据规则2,i的起始偏移量至少是9,且是其对齐数的整数倍。i的对齐数为min(sizeof(i), 8)=4。9不是4的整数倍,同理10,11都不是。故i的起始偏移量是12。又因为i的大小是4,故i的偏移量是12~15。

根据规则2,d2的起始偏移量至少是16,且是其对齐数的整数倍。d2的对齐数为min(sizeof(d2), 8)=8。16是8的倍数,故d2的起始偏移量是16。又因为d2的大小是8,故d2的偏移量是16~23。

根据规则2,c2的起始偏移量至少是24,且是其对齐数的整数倍。c2的对齐数为min(sizeof(c2), 8)=1。24是1的倍数,故c2的起始偏移量是24。又因为c2的大小是1,故c2的偏移量是24。

根据规则3,a的总大小至少是25(偏移量0~24),且是其最大对齐数的整数倍。最大对齐数是以上算出来的对齐数的最大值,即8。而25不是8的倍数。比25大的整数中,最小的8的倍数是32,故a的总大小是32个字节。

对于有嵌套结构体的情况同理。朋友们可以自行验证。

四、枚举类型

4.1 定义

枚举,即一一列举。比如三原色,就是红绿蓝。我们就声明一个枚举类型。


enum Color
{RED,GREEN,BLUE
};

从而定义枚举变量。


enum Color c;

和结构体类似,也可以在声明时定义。


enum Color
{RED,GREEN,BLUE
}c;

4.2 初始化

可以使用枚举常量来初始化枚举变量。如:


enum Color c = GREEN;

注意:枚举常量,默认从0开始,从上到下依次递增。如对于enum Color类型,RED的值是0,GREEN的值是1,BLUE的值是2。

五、联合体类型

5.1 定义

联合体类型的成员变量公用同一块空间,并且遵守内存对齐规则。如:


union U
{int i;char c;
};

这个类型大小是4个字节,其中i占满全部的4个字节,而c只占第一个字节,它们共用同一块空间,所以联合体又叫做共用体。

5.2 访问

访问方式和结构体类似。如:


union U u;
u.i = 10;

相关文章:

深入探索C语言自定义类型:打造你的编程世界

一、什么是自定义类型 C语言提供了丰富的内置类型&#xff0c;常见的有int, char, float, double, 以及各种指针。 除此之外&#xff0c;我们还能自己创建一些类型&#xff0c;这些类型称为自定义类型&#xff0c;如数组&#xff0c;结构体&#xff0c;枚举类型和联合体类型。 …...

Opencv基于文字检测去图片水印

做了一个简单的去水印功能&#xff0c;基于文字检测去图片水印。效果如下&#xff1a; 插件功能代码参考如下&#xff1a; using namespace cv::dnn; TextDetectionModel_DB *textDetector0; void getTextDetector() {if(textDetector)return;String modelPath "text_de…...

jdbc235

概念&#xff1a;java database connectivity java数据库连接 java语言操作数据库 定义了一套操作所有关系型数据库的规则&#xff08;接口&#xff09; 本质&#xff1a;其实是官方公司定义了一套操作所有关系型数据库的规则&#xff0c;即接口。各个数据库厂商去实现这套接…...

库仑定律和场强

1、库伦定律 两个电荷相互作用的力。 力是矢量&#xff0c;有大小和方向。 1.1、力的大小 1.2、力的方向 在两个电荷的连线上&#xff0c;同种电荷相互排斥&#xff0c;异种电荷相互吸引。 真空&#xff0c;不是必要条件&#xff0c;修改公式中介电常数的值仍然满足库伦定律。…...

Android安卓实战项目(13)---记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末)

Android安卓实战项目&#xff08;13&#xff09;—记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用&#xff01;&#xff01;&#xff01;&#xff08;源码在文末&#x1f415;&#x1f415;&#x1f415;&#xff09; 一.项目运行介绍 B站…...

嵌入式开发之syslog和rsyslog构建日志记录

1.syslogd作客户端 BusyBox v1.20.2 (2022-04-06 16:19:14 CST) multi-call binary.Usage: syslogd [OPTIONS]System logging utility-n Run in foreground-O FILE Log to FILE (default:/var/log/messages)-l N Log only messages more urge…...

Jaeger的经典BUG原创

前端&#xff0c;笔者在使用Jaeger进行Trace监控的时候&#xff0c;当数据量增大到一定数量级时&#xff0c;出现了一次CPU暴增导致节点服务器挂了的经典案例&#xff0c;这里对案例进行一个简单的抽象&#xff0c;供大家参考&#xff1a; 首先通过pprof对耗时的函数进行定位&…...

四款简洁好看 自适应的APP下载单页源码

分享四款简洁好看 自适应的APP下载单页源码&#xff0c;采用了底部自动获取ICP备案号&#xff0c;还有蓝奏云文件直链解析。不光可以做APP下载引导页&#xff0c;也可以随便改下按钮做网站引导页&#xff0c;自由发挥即可&#xff01; 蓝奏云直链解析的好处&#xff1a;APP放在…...

【服务器】交换机带外管理和带内管理

一、交换机的带外管理是什么&#xff1f; 在带外管理模式中&#xff0c;网络的管理控制信息与用户网络的承载业务信息在不同的逻辑信道传送。 带外管理最大的优势在于&#xff0c;当网络出现故障中断时数据传输和管理都可以正常进行——不同的物理通道传送管理控制信息和数据…...

Kotlin的内置函数 apply、let、run、with、also

let 1.let函数返回类型&#xff0c;是根据匿名函数的最后一行变化而变化 2.let函数中的匿名函数里面持有的是it 集合自身 fun main() {var num1 1var num2 1var result:Intresult num1 num2var str result?.let {//传入本身&#xff0c;it指代本身即result,result不为空…...

2023年人工景点行业研究报告

第一章 行业概况 1.1 定义及分类 人工景点行业通常指的是设计和构建的为提供娱乐、教育或文化体验的景点。这些景点可能包括主题公园&#xff0c;博物馆&#xff0c;动物园&#xff0c;水族馆&#xff0c;科学中心&#xff0c;历史遗迹&#xff0c;艺术展览等。这个行业通常包…...

react轮播图

这里 我用的是组件&#xff1a; 网址&#xff1a;Collapse 折叠面板 - Ant Design Mobile 1.首先 先声明一个变量 2、把需要的数据存存进去 3、组件内容复制过来&#xff08;这里用到的是map循环&#xff09; 然后图片就出来了 就是这个简单 哈哈哈哈&#xff01;&#xff01…...

Openlayers 叠加天地图-中国近海海洋等深面图层服务

Openlayers 叠加天地图-中国近海海洋等深面图层服务 核心代码完整代码&#xff1a;在线示例 偶然发现天地图有一个近海海洋图层&#xff0c;觉得不错&#xff0c;于是尝试叠加一下&#xff0c;花费了一些时间&#xff0c;叠加成功&#xff0c;这里分享一下。 本文包括核心代码…...

uniapp移动端h5设计稿还原

思路 动态设置html的font-size大小 实现步骤 先创建一个public.css文件&#xff0c;设置初始的font-size大小 /* 注意这样写 只能使用css文件, scss 是不支持的, setProperty 只适用于原生css上 */ html {--gobal-font-size: 0.45px; } .gobal-font-size {font-size: var(--g…...

后端数据配置相对路径,前端添加网站根 URL (根路径)- js获取网站项目根路径- 获取根路径后的第一个斜杠前 / 的项目- - 判断url包含某字符串

1、js获取网站项目根路径 js获取项目根路径&#xff0c;如下&#xff1a; 原 http://localhost:8080/testproject/test.html 根路径&#xff1a;http://localhost:8080 function getRootPath(){//获取当前网址&#xff0c;// 如&#xff1a; http://localhost:8080/testpro…...

deepspeed多机多卡并行训练指南

文章目录 前言离线配置训练环境共享文件系统多台服务器之间配置互相免密登录pdsh多卡训练可能会碰到的问题注意总结 前言 我的配置&#xff1a; 7机14卡&#xff0c;每台服务器两张A800 问&#xff1a;为啥每台机只挂两张卡&#xff1f; 答&#xff1a;给我的就这样的&#…...

9.Redis-zset

zset zset 有序集合 -> 升序常用命令zaddzcardzcountzrangezrevrange -> reverse 逆序zrangebyscorezpopmaxzpopminbzpopmax / bzpopminzrankzrevrankzscorezremzremrangebyrankzremrangebyscorezincrby集合间操作zinter -> 交集zunion -> 并集zdiff -> 差集zin…...

云计算的三个主要服务模型:IaaS、PaaS 和 SaaS

文章目录 介绍基础设施即服务&#xff08;Infrastructure as a Service&#xff0c;IaaS&#xff09;平台即服务&#xff08;Platform as a Service&#xff0c;PaaS&#xff09;软件即服务&#xff08;Software as a Service&#xff0c;SaaS&#xff09; 区别基础设施即服务&…...

spring ioc,DI,AOP概述

Spring是一个轻量级的Java开发框架。其中&#xff0c;IoC、DI和AOP是Spring框架的核心概念。 IoC&#xff08;Inversion of Control&#xff0c;控制反转&#xff09;&#xff1a;IoC是一种设计模式&#xff0c;是指将对象的创建、管理和控制权交给IoC容器&#xff0c;由IoC容器…...

meethigher-Apache Poi 实现Excel多级联动下拉框

由于最近做的功能&#xff0c;需要将接口返回的数据列表&#xff0c;输出到excel中&#xff0c;以供后续导入&#xff0c;且网上现有的封装&#xff0c;使用起来都较为麻烦&#xff0c;故参考已有做法封装了工具类。 使用apache poi实现excel联动下拉框思路 创建隐藏单元格&a…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...