C语言学习笔记——数组
前言
数组是C语言中的一种自定义数据类型,它的使用非常广泛。但是很多新手在使用数组时,经常在一些细节上出问题,导致程序崩溃或者无法编译。今天,我就来详细聊聊数组的使用和我注意到的一些细节。
一、常见的数组类型与数组的创建
1. 常见数组类型
与常见指针类型类似,常见的数组类型也是与常见的数据类型一一对应的,这里简单列举几个最常用的。
int arr1[10]; //整型数组
char arr2[20]; //字符数组
double arr3[5]; //双精度浮点型数组
struct stru arr[6]; //结构体数组
2. 数组的创建
int arr1[10]; //创建数组
int arr2[5] = {0,0,0,0,0}; //创建数组并完全初始化
int arr3[10] = {0}; //创建数组并不完全初始化
int arr4[] = {1,2,3,4,5}; //创建未给定大小的数组并初始化
我们以整型数组为例,上方为整形数组的四种创建与初始化方式。
首先来介绍第一行,也是最基础的数组创建方式,“数据类型 + 数组名 + [数组大小]”。其中,数组名和[ ]之间不能出现空格,数组大小只能为常量(可以为标识符常量)且只能为正整数。那么我们来解读第一行,就是一个名为“arr1”,可以存放10个整型数据的数组(数组大小为10个整型,即40个字节),该数组的数据类型为"int[10]"。
我们可以用“sizeof()”来计算数组在内存中占用的空间大小,如下图。
接下来看第二行,数组arr2为一个大小为5的整型数组,它的五个数据均被初始化为0。其中花括号中的第一个0即对应数组的第一个数据,称为数组的第一个元素,以此类推。
同理,第三行的arr3数组为一个大小为10的整型数组,它的第一个元素被初始化为0,剩余的9个元素未初始化。
第四行的arr4数组在创建时未给定大小,那么它的大小就由初始化的元素个数决定。由此得出arr4的大小为5。
补充:变长数组 (VS编译器不支持)
变长数组与常规数组的区别在于,常规数组在定义时,其数组大小只能为常量,而变长数组的大小可以为变量。因此,变长数组可以精准地开辟内存空间,从而避免空间浪费。
3. 字符数组的初始化
char ch1[] = {'a','b','c'};
char ch2[] = "abc";
字符数组可以按照常规数组初始化方式进行初始化,也可以按照上图第二行的方式,直接用字符串进行初始化。那么上图中的ch1,ch2的大小分别是多少呢?显然,ch1的大小为3,那么ch2的大小也为3吗?我们来看下图。
我们发现,数组ch2的大小为4,这又是为什么呢?我们不妨直接将这两个数组以字符串形式打印出来看看。
可以看见,第一行出现了许多乱码,而第二行则是正常的"abc"。这是为什么呢?关于这个问题,等到介绍数组在内存中的存储方式时,我再来详细解释。
二、数组元素的访问
当我们创建了一个数组后,我们应该如何调用数组中的元素呢?换句话说,如何访问数组的元素呢?
1. 下标引用操作符
// [] - 下标引用操作符 int arr[10];
arr[0] = 1;
数组的每个元素都有自己对应的下标,通过其下标即可访问该元素。我们可以通过下标引用操作符“[ ]”。如图,arr为一个大小为10的整型数组,当我们创建了数组之后,我们通过“数组名 + [元素下标]”,访问了arr数组中下标为0的元素,并将其赋值为1。
注意,上方代码中创建数组和访问数组元素均使用了“[ ]”,但这两个“[ ]”的含义不同,第一行的“[ ]”代表arr为一个"int[10]"类型的数组,而第二行的“[ ]”则是下标引用操作符,用来访问数组元素。
数组中第n个元素的下标为n-1,例如,第一个元素的下标为0。
2. 指针访问
int arr[10];
*(arr+1) = 2; //等价于: arr[1] = 2;
本质上,数组名就是指向数组起始地址的指针。由于数组arr为整型数组,故访问数组元素时,其数组名本质上为" int* "类型的指针,可通过指针的解引用操作符访问其指向的元素。图中“arr+1”即指针向后偏移一位,指向了数组中的第二个元素,因此等价于访问数组第二个元素。
int arr[10];
int* p = arr;
*(p+1) = 2;
同样地,我们也可以用其它指针储存arr所指向的地址,并通过该指针访问数组元素,如图中的指针p。
三、数组在内存中的存储
相信通过上面的访问方式,聪明的你一定已经猜到数组在内存中的存储形式了。数组在内存上占用一块连续的空间。我们通过VS的调试器来观察数组在内存中的存储,如下图。每个整型数据占用四个字节的空间,故地址每隔四存放一个数据。
而数组名arr即是首元素的地址,我们可以通过打印地址来查看。这也就解释了为什么数组元素可以通过指针的方式来访问。
接下来我们来解决之前字符数组留下来的问题。
通过监视窗口,我们可以看到,ch1中只有三个元素,相比之下,ch2多出了第四个元素'\0'。'\0'是一个字符,用来终止字符串。
由于ch2中存在'\0',打印ch2时才不会出现后面的随机值。而ch1中没有'\0',因此当ch1的元素全部打印完后,编译器会继续打印数组外的内容,由于未被赋值,这些内容通常为随机值,因此一直打印到遇到随机的'\0',打印才结束。
使用双引号" "引用的字符串的末尾都会自带一个'\0',这就是为什么用"abc"初始化ch2后会多出一个'\0'。
四、二维数组
1. 二维数组的创建
int arr1[3][3] = {0};
int arr2[][3] = {0};
二维数组有以上两种创建方式,其中前后两个“[ ]”中的数字我们分别称为行数和列数。二维数组的大小等于行数乘以列数。
在第一行中,我们给定了数组arr1的行数和列数,均为3,因此arr1的大小为9,即可容纳九个元素。同样,如果行数和列数都给定了,就可以选择不初始化。
在第二行中,我们给定了数组arr2的列数,但没有给定行数,这样一来数组的大小就根据初始化的值来确定了,如图中将第一个元素初始化为0,那么为了存储元素0,数组必须开辟一行的空间,由于一行有三列,因此数组arr2的大小为3。从中我们可以看出,为给定行数的二维数组的大小是由列数和初始化元素个数决定的。其大小必须为列数的整数倍,并且必须大于元素个数。
2. 二维数组元素的访问
int arr[3][3];
arr[0][0]=1;
二维数组的元素也是通过下标来访问的,只不过由于二维数组有行和列,因此下标也分为行标和列标。同样的,行标和列标也都是从0开始,如图中arr[0][0]即是访问第一行第一列的元素。
关于二维数组的指针访问,本文就不过多解释了,因为相对来说比较复杂,涉及到二维数组的原理。有兴趣的小伙伴可以自行推导。(提示:要用到二级指针)
3. 二维数组在内存中的存储
在我们理解二维数组时,我们把二维数组分成行和列,如上图。我们知道,一维数组在内存中是占用一块连续的空间。那么二维数组在内存中又是如何存储的呢?我们再次通过VS的内存窗口观察二维数组arr在内存中的存储情况。我们发现,二维数组在内存中也是连续存储的,并不是像我们理解的那样分为行和列来存储。
五、数组问题中一些常见的错误和技巧
1. 越界访问
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int a = arr[10];
我们来看上面这段代码。首先创建一个大小为10的整型数组并完全初始化,然后创建一个整型变量a,并初始化为arr数组中下标为10的元素。但是数组arr的大小为10,那么它最大的下标应该为9,也就是说不存在下标为10的元素。这就是所谓的越界访问。
由于数组创建时只开辟了10个整型大小的合法空间,而上方代码访问了第11个整型的空间,因此形成非法访问。
2. 初始化与修改数组元素
//错误示范
int arr[] = {1,2,3,4,5};
arr = {1,2,3,0,0};
char ch[] = "hello";
ch = "world";//正确做法
int arr[] = {1,2,3,4,5};
arr[3] = 0;
arr[4] = 0;
char ch[] = "hello";
ch = strcpy(ch,"world");
在讲数组的初始化时,我提到可以使用花括号和字符串进行初始化。但是要注意,当数组创建完毕并初始化后,就不能再使用花括号或字符串来修改数组了。如果数组创建完成后需要修改数组元素,则需通过下标访问需要修改的元素进行修改,若需要整体修改则可借助循环遍历数组。
3. 数组传参
void test(int* arr)
{arr[0] = arr[1];
}int main()
{int arr[3] = {0,1,2};test(arr);return 0;
}
之前介绍访问数组的方法时就提到,数组名其实就是指向数组首地址的指针,也就是说,数组传参其实也就等价于指针传参。在声明函数的参数时,若需接受数组,只需要声明一个同类型的指针变量即可。
结束语
以上就是我对数组的一些基础知识的总结啦。关于数组,我个人还是更喜欢将其理解为指针的一种变体,因为C语言中,指针可以说与内存息息相关,而数组则是通过一个指针(数组名)来管理该数组空间内的所有数据。不知道大家都是如何理解的呢?欢迎在评论区留言。
相关文章:
C语言学习笔记——数组
前言 数组是C语言中的一种自定义数据类型,它的使用非常广泛。但是很多新手在使用数组时,经常在一些细节上出问题,导致程序崩溃或者无法编译。今天,我就来详细聊聊数组的使用和我注意到的一些细节。 一、常见的数组类型与数组的创建…...
类和对象 - 中
本文已收录至《C语言》专栏! 作者:ARMCSKGT 目录 前言 正文 构造函数 对比C和C的初始化 构造函数的使用与特性 默认构造函数 C11关于默认构造缺陷的补丁 析构函数 析构函数特性 默认析构和自定义析构 拷贝构造函数 问题聚焦 拷贝构造的定…...
Android之屏幕适配方案
在说明适配方案之前,我们需要对如下几个概念有所了解:屏幕尺寸,屏幕分辨率,屏幕像素密度。 屏幕尺寸 屏幕尺寸指屏幕的对角线的物理长度,单位是英寸,1英寸2.54厘米。 比如常见的屏幕尺寸:5.0、5…...
SpringBoot+jersey跨域文件上传
一、配置tomcat服务器 1.1、添加upload文件夹 在webapps\Root文件夹下创建用于接收上传文件的upload文件夹 1.2、修改conf\web.xml设置允许上传文件 <init-param><param-name>readonly</param-name><param-value>false</param-value></ini…...
数据结构One——绪论
本喵是FW视频封面最终版宝子,你不点个赞吗?不评个论吗?不收个藏吗? 最后的最后,关注我,关注我,关注我,你会看到更多有趣的博客哦!!! 喵喵喵&#…...
JVM篇之内存及GC
目录一、JVM内存区域1.1程序计数器1.2虚拟机栈1.3本地方法栈1.4堆1.5方法区二、JVM运行时内存2.1新生代(轻量级GC)2.2老年代(重量级GC)一、JVM内存区域 JVM 内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法栈】、线程共享区域【JAVA 堆、…...
Linux驱动操作地址(寄存器)的一些方式
Linux驱动操作地址(寄存器)的一些方式 文章目录Linux驱动操作地址(寄存器)的一些方式1.对绝对地址赋值操作2. ioremap2.1 void __iomem *地址2.2 volatile unsigned int *地址2.3 structioremap1.对绝对地址赋值操作 对绝对地址0x100000赋值操作 *&…...
Java日志框架介绍
Log4j Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Glc首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。 Log4j 2 Apache Log4j 2是apache开发的一款Log4j的升级产品。 Commons Logging Apache基金会所属的项目,是…...
编程中遇到的计算机大小端概念
概念大小端(Endian)是指在一个多字节的数据中,字节的存储顺序的规定。通俗来说,就是指数据在计算机内部存储时的顺序问题。在计算机系统中,一个数据项可能占据多个存储单元。在这种情况下,这个数据项的存储…...
日志与可视化方案:从ELK到EFK,再到ClickHouse
EFK方案 从ELK谈起 ELK是三个开源软件的缩写,分别表示:Elasticsearch,Logstash,Kibana。新增了一个FlieBeat,它是一个轻量级的日志收集处理工具,FlieBeat占用资源少,适用于在各个服务器上搜集…...
字符函数和字符串函数(上)——“C”
各位CSDN的uu们你们好呀,今天小雅兰来给大家介绍一个全新的知识点,就是字符函数和字符串函数啦,其实其中有些函数我之前已经学习过了,比如strlen、strcpy;也有一些之前不是很熟悉的函数,比如strstr、strtok…...
九龙证券|下周解禁市值超400亿元,3股解禁压力较大
下周3股解禁比例超50%。 百利电气昨日盘中直线拉升封板,至此,百利电气两连板,累计涨幅20.85%。 昨日晚间,百利电气发布股票交易反常动摇公告称,公司不触及“室温超导”相关业务,也未打开相关研发和投入。公…...
一个大型网站架构的演变历程
正序: Rome was not built in a day(罗马不是一天建成的。)一个成熟的大型网站从来都不是一蹴而就的,需要经过多次架构的调整和升级,我们熟知的大型网站比如京东、淘宝、亚马逊,它们每天都有巨大的用户访问…...
前端前沿web 3d可视化技术 ThreeJS学习全记录
前端前沿web 3d可视化技术 随着浏览器性能和网络带宽的提升 使得3D技术不再是桌面的专利 打破传统平面展示模式 前端方向主要流向的3D图形库包括Three.js和WebGL WebGL灵活高性能,但代码量大,难度大,需要掌握很多底层知识和数学知识 Threej…...
链表经典笔试题(LeetCode刷题)
本篇文章主要是对力扣和牛客网上一些经典的和链表有关的笔试题的总结归纳,希望对你有所帮助。 目录 一、移除链表元素 1.1 问题描述 1.2 思路一 1.2.1 分析 1.2.2 代码 1.3 思路二 1.3.1 分析 1.2.3 思路三 1.3 代码实现 1.3.1 思路1的代码 1.3.2 思路2的…...
SpringCloud五大组件
微服务SpringCloud整合技术组件基本流程: 引入组件启动器依赖坐标覆盖默认配置即application.properties配置文件(每个微服务只有一个并且服务启动默认加载)引导类(微服务入口即main方法)自定义开启组件注解 SpringCloudEureka 服务注册中心,分为Eure…...
Echart的使用初体验,Echarts的基本使用及语法格式,简单图表绘制和使用及图例添加【学习笔记】
Echart? ECharts 是一个使用 JavaScript 实现的开源可视化库,涵盖各行业图表,满足各种需求。 ECharts 遵循 Apache-2.0 开源协议,免费商用。 ECharts 兼容当前绝大部分浏览器(IE8/9/10/11,Chrome…...
聊聊腾讯T13技术专家被开除
这两天腾讯的技术大佬stonehuang被曝离开腾讯,据他老婆在小红书上发的帖子称是遭遇了裁员,说实话刚看到这个消息我挺震惊的,stonehuang在中国大前端领域是排得上号的专家,同时他2005年就加入了腾讯,在qq空间的发展历程…...
c++ 常见宏、模板用法【1】
目录1、宏定义实现简单的断言2、可变参数模板3、变量模板4、宏定义实现范围内的for循环5、模板实现函数对象6、宏定义实现作用域限定7、类型萃取模板1、宏定义实现简单的断言 #define ASSERT(expr) \if(!(expr)) { \std::cout << "assertion failed: " <&l…...
【25】Verilog进阶 - 序列检测
VL25 输入序列连续的序列检测 本题并不难【中等】难度给高了 【做题关键】 (1)需要使用移位寄存器的思路。其实reg型是寄存器,也可以当做是移位寄存器,重要的是对其的处理,使用的是移位寄存器的思路 (2)注意新移入数据存放在低位 1 题目 + 代码 + TestBench 很简单,没…...
如何绕开运营商的 QoS 限制
运营商针对 UDP 进行限制,这是 QUIC 以及类似 UDP-Based 协议的推广阻力之一,上了线很多问题,丢包,慢等的问题严重增加运维,运营成本。 按照运营商五元组 QoS 这种简单粗暴不惹事的原则,只要换一个端口就可…...
C#基础教程22 异常处理
文章目录 C# 异常处理语法C# 中的异常类异常类 描述异常处理创建用户自定义异常C# 异常处理 异常是在程序执行期间出现的问题。C# 中的异常是对程序运行时出现的特殊情况的一种响应,比如尝试除以零。 异常提供了一种把程序控制权从某个部分转移到另一个部分的方式。C# 异常处理…...
java八股文--java基础
java基础1.什么是面向对象,谈谈对面向对象的理解2.JDK JRE JVM的区别与联系3.和equals4.hashCode与equals5.String StringBuffer StringBuilder的区别6.重载和重写的区别7.接口和抽象类8.List和Set的区别9.ArrayList和LinkedList10.HashMap和HashTable的区别&#x…...
2022年全国职业院校技能大赛(中职组)网络安全竞赛试题A模块第四套解析(详细)
2022年全国职业院校技能大赛(中职组) 网络安全竞赛试题 (4) (总分100分) 赛题说明 一、竞赛项目简介 “网络安全”竞赛共分A.基础设施设置与安全加固;B.网络安全事件响应、数字取证调查和应用安全;C.CTF夺旗-攻击;D.CTF夺旗-防御等四个模块。根据比赛实际情况,竞…...
【Spark】spark使用jdbc连接带有kerberos认证的hive jdbc
背景 这个需求就是spark不通过spark-hive的方式访问hive数据,而是通过spark读取hive jdbc的方式访问hive数据,因为这个hive有kerberos认证,在网上也不是很容易搜索到这样的操作案例。不多bb,直接上教程。 准备工作 准备一个hiv…...
【Maven】项目中pom.xml坐标定义以及pom基本配置
目录 一、pom.xml坐标定义 二、pom 基本配置 一、pom.xml坐标定义 在 pom.xml 中定义坐标,内容包括:groupId、artifactId、version,详细内容如下: <!--项目名称,定义为组织名项目名,类似包名-->&l…...
Linux GCC 编译详解
文章目录一、GCC 编译器简介二、GCC 工作流编程语言的发展GCC 工作流程gcc 和 g 的区别三、使用 GCC 编译GCC 编译格式GCC 编译流程多个源文件编译一、GCC 编译器简介 首先,什么是编译器呢? 我们可以使用编辑器(如 linux 下的 vi、windows 下…...
谁说程序员不懂了浪费,女神节安排
Python的PyQt框架的使用一、前言二、女神节文案三、浪漫的代码四、官宣文案一、前言 个人主页: ζ小菜鸡大家好,我是ζ小菜鸡,特在这个特殊的日子献上此文,希望小伙伴们能讨自己的女神欢心。 二、女神节文案 1.生活一半是柴米油盐,…...
上市公司管理层短视指标(2007-2020)
1、数据说明:将研发⽀出的减少量(∆R&D)作为管理层短视⾏为的度量指标,即∆R&D为公司t年的研发⽀出减去t-1年的研发⽀出并除以t-1年末的总资产再乘以100。2、数据来源:自主整理3、时间跨度:2007-20…...
IDDPM 和 DDIM 对比
IDDPM 和 DDPM 对比IDDPMDDIMIDDPM IDDPM:Improved Denoising diffusion probabilistic models learning Σθ\Sigma_{\theta}Σθ, 即Σθ(xt,t)exp(vlogβt(1−v)logβ~t)\Sigma_{\theta}\left(x_{t}, t\right)\exp \left(v \log \beta_{t}(1…...
怎样给网站或者商品做推广/网站首页排名seo搜索优化
遍历文件夹中的所有子文件夹及子文件使用os.walk()方法非常简单。 语法格式大致如下: os.walk(top[, topdownTrue[, onerrorNone[, followlinksFalse]]]) top – 根目录下的每一个文件夹(包含它自己), 产生3-元组 (dirpath, dirnames, filenames)【文件夹路径, …...
如果在阿里云上做自己的网站/苏州百度推广排名优化
首先查看系统的操作位数uname -a确定自己的系统位数一 、卸载自身yum #rpm -aq|grep yum|xargs rpm -e --nodeps 下载网易的centos的rpm包http://mirrors.163.com/centos/6/os/x86_64/Packages/python-iniparse-0.3.1-2.1.el6.noarch.rpmhttp://mirrors.163.co…...
福田网站建设龙岗网站建设龙岗网站建设/爱站网域名查询
【流媒体网】消息:消费者需求与产业链升级,永远是敦促技术进步的两大源动力。在视频应用与消费领域,显示效果、播出质量和观看体验的不断提升、人机界面与互动模式的“虚拟-真实”化演进,是决定“下一代视频”技术与应用进步的两个…...
山东省旅游局网站建设情况/品牌营销策划书
Maven学习总结(五)——聚合与继承 一、聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1、聚合配置代码 1 <modules> 2 <module>模块一</module> 3 <module>模块二</module> 4 <mo…...
wordpress喜欢 赏 分享/如何在百度提交自己的网站
广州商学院 计算机系 系(部) 2015 — 2016 学年第(1)学期 《软件工程》课程设计 一、课程简介及基本要求 软件工程是一门指导软件开发和维护的工程学科,主要内容包括:软件项目管理、结构化分析和设计、面向…...
在福州的网站制作公司/推广软件app
转自:http://blog.csdn.net/cpf2016/article/details/45534527 1.相关概念 (1)webx中的MVC 在webx中control就是action,view和layout、control、screen、template等概念相关。 layout指页面布局;control指页头、页脚、…...