为什么很多编程语言中数组都是从 0 开始编号
正文
1 为什么很多编程语言中数组都是从 0 开始编号
1.1 效率原因
从内存模型来看,“下标”也称为“偏移”。
我们知道在C语言中数组名代表首地址(第一个元素的地址),a[0]就是偏移为 0 的位置。a[k]就表示偏移 k 个元素类型大小的位置。得出计算公式:
a[k]_address = base_address + k * type_size
但是钥匙从 1 开始计数,那这个公式就会变为:
a[k]_address = base_address + (k-1) * type_size
对比两个公式,如果从 1 开始编号,每次随机访问数组元素就多了一次减法运算,对于CPU来说就是多了一次减法指令。
数组作为非常基础的数据结构,通过下标访问数组元素又是数组上的基础操作,效率优化应做的很好,所以为了减少一次减法操作,数组选择了从 0 开始编号。
1.2 历史原因
C语言的设计者用 0 开始计数下标,之后的Java、C++等高级语言都效仿C语言,沿用了从0开始计数的习惯。
还有一些语言并不是从0开始计数的,如:Matlab。
据我所知:python还支持负数下标。
2 数组的特点
2.1 随机访问
数组是一种线性数据结构,占用一段连续的内存,存储相同类型的数据。
例如:这样一段代码
int arr[10] = { 0 }; for (int i=0; i<10; i++) {arr[i] = i; }
查看数组信息:(addr=0x7ffeefbff530, size=40, variable expression=‘arr’).
我们再来打断点看看内存情况:
看内存情况我们得到:
arr共使用40字节内存,首地址为0x7ffeefbff530
arr[0]地址为:0x7ffeefbff530
arr[9]地址为:0x7ffeefbff554
每个int有4个字节,故arr[9]结尾为0x7ffeefbff558
0x7ffeefbff558-0x7ffeefbff530 = 24 16进制
(28)16->(40)10
数组随机访问时:通过计算元素存储位置的内存地址来访问相应的元素
a[i]_address = base_address + i * data_type_size
数组支持随机访问,根据下标随机访问的时间复杂度为O(1)。
2.2 低效的“插入”和“删除”
2.2.1 低效原因
数组为了保持内存数据的连续性,会导致插入、删除这两个操作比较低效。
插入:
假设数组长度为n,要将一个数据插入到第 k 个位置,为了把第 k 个位置腾出来,我们需要将k~n这部分元素顺序的向后移动一位。
插入的时间复杂度:
最好情况:在数组的末尾插入元素,不需要移动数据了,时间复杂度为O(1)。
最坏情况:在开头插入元素,那就需要把所有的数据向后移动一位,时间复杂度为O(n)。
平均时间复杂度:(1+2+…+n)/n = O(n)。
删除:
删除操作和插入操作类似,删除了某一元素后,需要搬移数据。
和插入类似,如果删除数组末尾的数据,则最好情况时间复杂度为O(1),如果要删除开头数据,则最坏情况时间复杂度为O(n),平均时间复杂度为O(n)。
2.2.2 改进方法
插入:
如果数组中的元素没有任何规律,数组只是被当作一个数据集合,在这种情况下,如果要将某个数据插入到第k个位置,为了避免大规模的数据迁移,一个简单的办法就是直接将现在第k个元素放到最后,把新元素放进来。*
例如:
arr[10] = {a,b,c,d,e}
要将x插入第三个位置arr[10]={a,b,x,d,e,c}
这样插入的时间复杂度为O(1),这种方法在快速排序中也会用到。
删除:
在某些特殊情况下,我们并不一定非得追求数组中数据的连续性,如果我们将多次删除操作放在一起执行,效率会高很多。*
举个例子:
a[10]={a,b,c,d,e,f,g,h}
如果我们要依次删除abc三个元素,需要搬移三次后面的数据,为了避免这个重复的搬移工作,可以先记录下来已经删除的数据,每次的删除操作并不是真正的搬移数据,只是记录数据已经被删除,当数组中没有更多的空间存储数据时,我们再触发执行一次真正的删除操作,这样就大大减少了搬移工作,这也是标记清除垃圾回收算法的核心思想。
3 数组越界问题
有如下代码:
int main(int argc, char* argv[]){int i = 0;int arr[3] = {0};for(; i<=3; i++){arr[i] = 0;printf("hello world\n");}return 0; }
这段代码的结果并不是打印三行hello world,而是无限打印hello world。
为啥呢?
因为在C语言中,除了受限制的内存,其他所有内存空间都是可以自由访问的。
那为什么会无限打印呢?
根据我所学和百度的知识解释下:函数体内的局部变量存在栈区,在Linux内存布局中,栈区在高地址空间,从高到低增长,先
int i = 0;
再int arr[3]={0};
变量i和arr地址相邻,并且i地址比arr地址大,首先压栈的i,a[2],a[1],a[0],循环中arr访问越界正好到i,而此时i变量的地址是数组当前进程的,所以进行修改的时候,操作系统并不会终止进程。当然这只是32位操作系统下,64位操作系统下 默认会进行8字节对齐 变量i的地址就不紧跟着数组后面了。另外这个还和编译环境有关,对于不同的编译器,在内存分配时,会按照内存地址递增或递减的方式进行分配。如果是内存地址递减的方式,就会造成无限循环。
4 容器和数组用哪个更好
对于数组类型,很多语言提供了容器类,例如我正在学的C++中的Vector。
那什么时候用数组,什么适合用容器呢?
容器的优势就是可以将很多数组操作的细节封装起来,有的还支持动态扩容。
王争老师:如果特别关注性能,或者数据大小已知,且对数据操作非常简单,用不到容器提供的大部分方法,可以是用数组。
完,不足之处请指正。
为什么很多编程语言中数组都是从 0 开始编号相关推荐
- 为什么很多编程语言中数组都从0开始编号
寻址方式的原因 从数组存储的内存模型上来看,"下标"最确切的定义应该是"偏移(offset)". 如果用 a 来表示数组的首地址,a[0]就是偏移为 0 的位置 ...
- 05 | 数组:为什么很多编程语言中数组都从0开始编号?
什么是数组? 数组(Array)是一种线性表数据结构.它用一组连续的内存空间,来存储一组具有相同类型的数据. 线性表存储结构 连续内存空间 存储相同类型数据 优点:连续内存+相同类型数据=数组可以实现 ...
- 为什么数组都是从0开始?
我们所知的大部分编程语言中,数组都是从0开始的,但你是否思考过,为什么数组从0开始编号,而不是1开始呢?从1开始不是更符合我们的日常习惯吗? 什么是数组 数组(Array)是一种线性表数据结构.它用一 ...
- java数组下标0_Java语言中数组元素下标从0开始。
[单选题]规范规定,硅酸盐水泥的初凝时间不小于( ). [判断题]打开/关闭"对象追踪"的功能键是F11. [判断题]break语句的作用是结束当前的循环体. [单选题]项目标识代 ...
- 1. 数组:为什么数组要从0开始编号,而不是1开始呢?
1. 数组:为什么很多编程语言中数组都是从0开始? 在大部分编程语言中,数组都是从0开始编号的,但你是否下意识想过,为什么数组要从0开始编号,而不是1开始呢? 从1开始不是更符合人类的思维习惯吗?下面 ...
- 为什么很多编程语言数组从0开始
数组 什么是数组 如何实现随机访问 低效的插入和删除 警惕数组越界 关于容器和数组 什么是数组 什么是数组?它的定义就是线性表+连续的内存空间+相同数据类型的数据. 什么是线性表?线性表就是数据排成像 ...
- c语言如何用指针操作一维字符数组,C语言中数组和指针的互操作
C是一种怀旧的语言,因为它的历史很久远,然而自从各种面向对象的编程语言的相续出现让它的影响力日减.当然了,这是无可非议的,但是C的高效性是其他语言无妨比拟的,所以我们有必要把握其中的精华与奥妙,也就有 ...
- c语言中的下标变量是什么,c语言中数组的下标从什么开始?
c语言中数组的下标从0开始. 数组中的各元素的存储是有先后顺序的,它们在内存中按照这个先后顺序连续存放在一起.数组元素用整个数组的名字和它自己在数组中的顺序位置来表示. 例如:a[0]就表示名字为a的 ...
- C语言中数组长度的计算详解
一. C语言中计算数组长度大小 C语言字符串长度的计算可以使用strlen(str); 但是对于数组长度的大小却没有相关函数可以使用: C语言数组长度的大小可以使用: int main() {int ...
最新文章
- php mysql 500错误日志_服务器出现500错误的时候,让PHP显示错误信息
- 内存256KB设备也能人脸检测,微软提出用RNN代替CNN | NeurIPS 2020
- 《BI那点儿事》三国人物智力分布状态分析
- 怎么样才能写出出色的代码
- VS2019安全函数scanf_s问题
- 信息学奥赛一本通(1037:计算2的幂)
- 旧闻新看 ---- 西门子为什么要收购TESIS PLMWare
- 【codevs1565】【BZOJ2242】计算器,数论练习
- 这是一篇很好的文章,学verilog的可以好好看看
- 【CLR】解析AppDomain
- 计算机组成原理—主存储器与cpu的连接
- 湖北省地税应用灾备中心正式启用
- 【leetcode】杨辉三角Ⅱ
- mysql建表常用sql语句
- Java读取配置文件Java加载不同环境的配置文件
- 实践三 网络嗅探与协议分析
- epub文件一揽子解决方案
- 利用archetype创建maven脚手架和新项目
- 关于淘宝的数据库系统
- 公司没大牛带,需要离职么?
热门文章
- 修马达的php源码,查看SKU:RB-02S087 振动马达模块的源代码
- Jim Williams神作:The Art and Science of Analog Circuit Design.pdf文件免费分享
- 《高效学习魔法书》——读书笔记
- 信息技术第二单元传统动画与计算机动画比较,传统动画与Flash动画设计的优缺点对比...
- linux docker查找镜像文件,搜索/下载/构建自定义/删除Docker镜像,运行和删除Docker容器的方法...
- c8051f120相关
- 现代ups电源及电路图集_现代UPS电源及电路图集
- Python-OpenCV中的图像处理 » 轮廓:入门
- Elasticsearch:异步搜索 - async search
- 淮海工学院计算机考试题库,淮海工学院数据库试卷.docx