arraylist下标从几开始_漫画:为什么计算机从 0 开始计数,而不是从 1 开始?

ed5f63af5990ca312a222978609b301e.png

作者 | 漫话编程

来源 | 漫话编程

da5220334ad91a1db68464c29155d946.pngb4a1b73d0293181e734ac4b2de287c6c.png9153bdfc3d0604be2323ac29b9b741de.png1807537534d1ba25cf29585535665c7b.pnge30637574f4ee804e5a5f15e29dd17ff.png

当我们想要写一个循环体,期望执行10次的时候,我们会使用以下方式:

for (int i=0; i<10; i++){

}

可以看到,为了保证循环10次,我们定义了一个整数变量从0开始。

还有,当我们定义数组的时候,在常见的C语言、Java、Python等语言中,都是使用下标0来表示第一个元素的。

05390121837744e3fd0f5a3c97d93a42.png373c25ccbfc47ce86dc4e8acab921477.png41d7f78168270c43012e41a1a1371a01.pngafa635e95fa050853ef8e7136a0cfc52.pngbcefa7f0f2ec42e93e8911d30021f003.png

从0开始更优雅

在《为什么程序员喜欢使用0 ≤ i < 10这种左闭右开的形式写for循环?》一文中我们分析过,Dijkstra通过分析,得出在进行范围表达的时候,使用左闭右开的方式更加合理。

但是,Dijkstra在分析出2 ≤ i < 13这种形式更加合理之后,他有陷入了另外一个思考,那就是:

当处理长度为 N 的序列时,到底第一个元素的下标使用0还是1更加合适?

关于这个分析,他的出发点很简单,那就是哪种方式更加漂亮,更加优雅。

他认为,使用左闭右开的表达方式,当下标从 1 开始时,下标范围为 1 <= i < N+1;当下标从 0 开始时则是 0 <= i < N;

而显然后面这种表达式更加漂亮、优雅一些。所以,他建议我们使用0作为第一个下标。

3112149eb4afd8e56717216f4d4ae70e.pnge592804b421e2655132b78c435cec1f4.png5f40d658614a2cd0aca4d3deeddc401b.png3cfbea68e2805c7d6df3ada4f4ab123c.png16628fbba27fa6b11f5b1c201479bd7b.png

计数表示偏移量

很多人学习编程都是从C语言开始的,那么,C语言就是一个典型的0-base语言(以0作为计数的开始),其实,这一约定早在BCPL时代就是这样的了。

在C语言还不叫C语言,还叫BCPL的时候,他的作者马丁·理察德就设计了数组从0开始的索引方式。

当我们在BCPL(C语言)中定义数组int arr[8]的时候,编辑器会在内存中开辟一块空间(这个空间中可能包含多个内存单元)供该数组使用。

为了能让数组找到编译器为自己开辟的空间,会把这块内存空间中第一个内存单元的地址(0X0000001)赋值给这个数组,当我们使用&arr的时候,就可以拿到这块地址。

0ad7db99d51214d81c97dc332322410b.png

BCPL最初是用IBM 7094机器编译的;它在编译时会优化这些数组索引提供的指针反参考运算(indirection),即可以通过指针取出地址中存储的值,这个特性也一直延续到今天。

有了指针之后,我们可以使用int *pr = arr的方式初始化一个指针,那么,这时候,指针pr也会指向数组的内存空间的第一个内存单元的地址。

39f56d20c707bc5a42398e48a038f153.png

那有了数组和指针,想要使用这块内存第一个内存单元存储一个变量的时候,就需要想办法表示这第一个空间。

那么,BCPL的作者采用了0作为数组第一个元素的下标,因为他认为,数组的下标应该和指针的偏移量是相对应的。这样在使用第一个内存单元的时候,直接使用arr[0]或者*(p+0)就可以了。

5c971dd3c30fdc7adb68033cbddab1f1.png54c1432e8a753e75ffe67616028f436f.pngb8c250a5129cce596d1e8cdf35ec4df3.png

因为指针 *(p+0) 这种表达形式中的0表示的是偏移量,所以,无论数组的下标从几开始, *(p+0) 都是用于存取内存中的 p+0位址的值,也就是0X0000001这块内存单元的值。

试想一下,如果使用1作为数组的起始下标,那么arr1就应该指向0X0000001这块内存,但是 *(p+1) 按照偏移量的计算方式,需要指向0X0000005这块内存。这种情况下,如果想要让 *(p+1)和arr[1] 指向同一块内存,就需要额外做一次减法指令。

因为几乎所有计算机结构,都借由位址和偏移量来表示直接引用内存,所以,像C语言这种使用0做为数组的第一个下标使得语言的实现上更加容易。

但是值得一提的是,在C语言流行起来之前,还是有很多1-base的编程语言的,如FORTRAN、BASIC等编程语言的数组下标都是从1开始的。

随着C语言的发扬光大,很多语言都参考了C语言的做法。

7d201215e77bd305a54fc032a71d6687.png8a083474d4c741be4dce768239555183.pngdcd5d7cba1f1c0142b871f3d93325fc0.pngac9d692a203f93d2b32c41805f52484f.png

Python作者的解释

关于这个问题,之前也有网友在Twitter上询问过Python之父——Guido van Rossum,他给出过正面回答,我把回答内容的翻译版贴在下面:

我记得自己就这个问题思考过很久;Python的祖先之一ABC语言,使用的索引是从1开始的(1-based indexing),而对Python语言有巨大影响的另一门语言,C语言的索引则是从0开始的。

我最早学习的几种编程语言(Algol, Fortran, Pascal)中的索引方式,有的是1-based的,有的是从定义的某个变量开始(variable-based indexing)。而我决定在Python中使用0-based索引方式的一个原因,就是切片语法(slice notation)。

让我们来先看看切片的用法。可能最常见的用法,就是“取前n位元素”或“从第i位索引起,取后n位元素”(前一种用法,实际上是i==起始位的特殊用法)。如果这两种用法实现时可以不在表达式中出现难看的+1或-1,那将会非常的优雅。

使用0-based的索引方式、半开区间切片和缺省匹配区间的话(Python最终采用这样的方式),上面两种情形的切片语法就变得非常漂亮:a[:n]和a[i:i+n],前者是a[0:n]的缩略写法。

如果使用1-based的索引方式,那么,想让a[:n]表达“取前n个元素”的意思,你要么使用闭合区间切片语法,要么在切片语法中使用切片起始位和切片长度作为切片参数。

半开区间切片语法如果和1-based的索引方式结合起来,则会变得不优雅。

而使用闭合区间切片语法的话,为了从第i位索引开始取后n个元素,你就得把表达式写成a[i:i+n-1]。

这样看来,1-based的索引方式,与切片起始位+长度的语法形式配合使用会不会更合适?这样你可以写成a[i:n]。事实上,ABC语言就是这样做的——它发明了一个独特的语法,你可以把表达式写成a@i|n。

但是,index:length这种方式在其它情况下适用吗?说实话,这点我有些记不清了,但我想我是被半开区间语法的优雅迷住了。

特别是当两个切片操作位置邻接时,第一个切片操作的终点索引值是第二个切片的起点索引值时,太漂亮了,无法舍弃。

例如,你想将一个字符串以i,j两个位置切成三部分,这三部分的表达式将会是a[:i],a[i:j]和a[j:]。

66bfab5b3b1aa8e75c2bba47ba6bb5ee.pngd7002528f63427a27f7471a580227348.png5a15aadc07fb2eb4d9a836cd84ff8503.png40614ee36f32fc0277f1c0bc4ab2d0b7.png9c41997d7cf5aaff308093aef8e7300e.pngda3d656a412b7c1de172311ff5eab0f2.png

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

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

相关文章

python 爬虫代码_Python 你见过三行代码的爬虫吗

Python 使用Lassie库&#xff0c;仅编写三行代码就能爬取静态页面上的图片和视频。Python实战教程每次讲爬虫的时候都会从“发送请求” 开始讲&#xff0c;讲到解析页面的时候可能大部分读者都会卡住&#xff0c;因为这部分确实需要一点XPATH或者CSS选择器的前置知识。那么有没…

接口传值后不起作用_聊一聊 API 接口测试

知其然亦知其所以然&#xff0c;接口测试没有那么复杂&#xff0c;但也没有那么简单。本文作者&#xff1a;张敏&#xff0c;软件测试工程师&#xff0c;就职于一家容器平台解决方案公司&#xff0c;负责 DevOps 产品的测试。什么是 APIAPI(Application Programming Interface)…

服务器无法在发送 http 标头之后设置内容类型。_python socket编程预知内容

socket&#xff1a;运用IP地址协议端口 标识一个进程我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程&#xff0c; 在本地进程通讯中我们可以使用PID来唯一标示一个进程&#xff0c;但PID只在本地唯一&#xff0c;网络中的两个进程PID冲突几率很大 …

自定义键盘组件_一文读懂!iOS系统组件的设计规范全解

一说到组件&#xff0c;大部分初级设计师和中级设计师的脑海里只会蹦出弹窗、Toast及操作列表等具体的概念&#xff0c;没有一套属于自己的组件分类体系&#xff0c;这样对于视觉设计、交互设计或产品设计的系统学习来说都是不利的。iOS14概念设计iOS官方设计指南在介绍组件时是…

anaconda安装python视频_怎么安装anaconda?

安装 Anaconda步骤&#xff1a; 1、双击下载好的 Anaconda2-5.2.0-Windows-x86_64.exe文件&#xff0c;出现如下界面&#xff0c;点击 Next 即可。2、点击 I Agree &#xff08;我同意&#xff09;3、Install for: Just me还是All Users&#xff0c;假如你的电脑有好几个 Users…

office365 自定义_IT外包观察,足不出户,Office365打造教学新体验?

Office365无疑是当今最高效的集文档处理、联机协同、移动办公、快捷沟通、商业智能为一体的云端生产力服务。但office365仅仅只应用于移动办公吗&#xff1f;有没有可能实现移动办学呢&#xff1f;仅仅是商业智能吗&#xff1f;会不会也能做到教学智能&#xff1f;上海蓝盟连续…

python连接数据库mysql错误1045、手动登录可以_登录mysql错误1045解决方法

在命令提示符中登陆mysql时&#xff0c;提示1045报错解决方案&#xff1a; 安装好mysql&#xff0c;在cmd中输入mysql -uroot -p回车&#xff0c;输入密码后&#xff0c;出现1045错误&#xff0c;错误提示如下&#xff1a; ERROR 1045(28000): Access denied for user rootloca…

host 端口_如何让多端口网站用一个nginx进行反向代理实际场景分析

前段时间公司要整合服务器资源&#xff0c;刚好趁这次机会将这些乱七八糟的服务器做一次梳理和整合&#xff0c;断断续续一个月迁移完成大概优化掉了1/3的机器&#xff0c;完成之后遇到了一些问题&#xff0c;比如曾今零零散散部署在生产上一些可视化UI&#xff1a;apollo&…

sqldeveloper导出数据字典_如何全面建设B端产品中的数据迁移方案

加关注&#xff0c;带你看世界在新系统替换老系统或者系统升级的项目中&#xff0c;难免会存在数据迁移的工作&#xff0c;并且随着业务系统和数据结构的复杂性&#xff0c;数据迁移的难度越大。这亦要求在项目实施的前期&#xff0c;根据客户的需求尽可能全面地考虑到各个方面…

声明对象_静态变量(使用同一个类声明的对象可以共享一个值)

要在属于同一种类的对象之间共享数据值&#xff0c;可以使用static。namespace demo3{ class point //定义点 { public int x; public int y; } class line { static public point origin new point(); public point ending ne…

centos6配置mysql远程访问_MariaDB 数据库配置 Navicat 程序远程访问权限

如果MySQL数据库采用的是 MariaDB 引擎&#xff0c;与普通的数据库配置有点不同 MariaDB 与普通的MySQL数据库的一个不同在于它的配置文件不止一个&#xff0c;它将不同的数据放入到不同的配置文件中&#xff0c;之前的/etc/mysql/my.cnf内容如下&#xff1a;从文件中的注释上来…

java读取mysql配置文件_Linux运维:MySQL读写分离解决方案

一次性付费进群&#xff0c;长期免费索取教程&#xff0c;没有付费教程。进微信群回复公众号&#xff1a;微信群&#xff1b;QQ群&#xff1a;460500587教程列表 见微信公众号底部菜单 | 本文底部有推荐书籍 微信公众号&#xff1a;计算机与网络安全ID&#xff1a;Computer-net…

的硬件报错_工程师经验:78%的硬件失效罪魁祸首 —— 焊接问题

工程师经验你是否长时间纠缠于线路板的失效分析&#xff1f;你是否花费大量精力在样板调试过程中&#xff1f;你是否怀疑过自己的原本正确的设计&#xff1f;也许许多硬件工程师都有过类似的心理对话。有数据显示&#xff0c;78%的硬件失效原因是由于不良的焊接和错误的物料贴片…

柔性体没有应变_灌注式半柔性道面材料抗冲击性能试验研究

文章来源&#xff1a;微信公众号"沥青路面”前言灌注式半柔性道面材料是一种刚度大于沥青混凝土&#xff0c;小于水泥混凝土的复合道面材料&#xff0c;在兼具了两种材料优势的同时避开了它们的缺陷。半柔性道面不存在裂缝&#xff0c;而且受温度影响远远小于沥青道面&…

html网页上传到服务器_JSP+Servlet实现文件上传到服务器功能

本文实例为大家分享了JSPServlet实现文件上传到服务器功能的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下项目目录结构大致如下&#xff1a;正如我在上图红线画的三个东西&#xff1a;Dao、service、servlet 这三层是主要的结构&#xff0c;类似 MVC 架构&#xff…

gaf处理一维故障信号_【推荐文章】改进局部均值分解的齿轮箱复合故障特征提取...

《机械传动》2019年 第43卷 第8期文章编号&#xff1a;1004-2539(2019)08-0130-05DOI&#xff1a;10.16578/j.issn.1004.2539.2019.08.024引用格式&#xff1a;柴慧理, 叶美桃. 改进局部均值分解的齿轮箱复合故障特征提取[J]. 机械传动, 2019&#xff0c;43(8):130-134.CHAI…

dll模块化设计与编程_FPGA设计原则经验分享

一、面积和速度如何折中 面积和速度是芯片设计中一对相互制约、影响成本和性能的指标&#xff0c;贯穿FPGA设计的始终。在FPGA设计中&#xff0c;面积是指一个设计消耗的FPGA内部逻辑资源的数量&#xff0c;可以用消耗的触发器和查找表的个数或者是等效逻辑门数来衡量&#x…

div背景透明_为什么css3实现background-image和半透明边框这么麻烦

”background和border属性能有什么难的&#xff1f;"我经常听到新手觉得css的background和border属性简单。那好&#xff0c;我们来看下面这个比较“简单”的需求&#xff1a;父元素有一张背景&#xff0c;子元素有边框&#xff0c;且子元素有一张背景颜色。这时候子元素的…

c mysql 查询超时设置_MySQL查询超时的设置方法

欢迎进入Linux社区论坛&#xff0c;与200万技术人员互动交流 >>进入 这里顺带解释一下什么是non-interactive connection Non-Interactive Commands Just do a quick look up on a table without logging into the client, running the query then logging back out aga欢…

python聚类分析案例_深度解读|如何构建用户分级体系实现精细化运营?附案例实操...

本文内容较长&#xff0c;代码全部已展示在文中用户精细化分类也可以称做用户画像&#xff0c;是目前很常见的一种运营手段&#xff0c;目的是为了更好的服务不同性质的客户&#xff0c;提高每个环节的转化率&#xff0c;最大程度挖掘客户价值&#xff0c;创造利润。那么如何构…