精华内容
下载资源
问答
  • 为什么数组都是从0开始

    千次阅读 2019-11-06 16:18:31
    我们所知的大部分编程语言中,数组都是从0开始的,但你是否思考过,为什么数组从0开始编号,而不是1开始呢?1开始不是更符合我们的日常习惯吗? 什么是数组 数组(Array)是一种线性表数据结构。它用一组连续的...

    我们所知的大部分编程语言中,数组都是从0开始的,但你是否思考过,为什么数组从0开始编号,而不是1开始呢?从1开始不是更符合我们的日常习惯吗?

    • 什么是数组
      数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。

    线性表(Linear List),见名知意,线性表就是数组排成一条线一样的结构。每个线性表上的数据只有前和后两个方向,其实除了数组,链表、队列、栈等也是线性表结构。
    amelia_ csdn首发
    而与之对立的概念就是非线性表,非线性表中有我们熟知的二叉树、图、堆等

    连续的内存空间和相同的数据类型。 线性表+连续的内存空间(相同数据类型),造就了数组的快速访问特性,当按照下标查找指定位置的数据时,时间复杂度达到了最优的 O(1),当访问不确定的数组时时间复杂度为 O(n)

    有了上面的基本介绍,接下来我们拿一个长度为 10 的 int 类型的数组 int[] a = new int[10] 来举例。分配了一块连续内存空间 100~139,其中,内存块的首地址为 first_address = 100。
    amelia_  csdn首发
    计算机会给每个内存成员分配一个地址,通过指定的地址来访问内存中的数据,当计算机随机访问数组中的某个元素时会进行西面的方式来进行寻址:

    a[i]_address = first_address + i * data_size
    

    data_size 表示元素大小。

    为什么大多数编程语言中,数组要从 0 开始编号,而不是从 1 开始呢?

    从数组存储的内存模型上来看,“下标”最确切的定义应该是“偏移(offset)”。前面也讲到,如果用 a 来表示数组的首地址,a[0] 就是偏移为 0 的位置,也就是首地址,a[i] 就表示偏移 i 个 data_size 的位置,所以计算 a[i] 的内存地址只需要用这个公式:

    a[i]_address = first_address + i * data_size
    

    但是,如果数组从 1 开始计数,那我们计算数组元素 a[i] 的内存地址就会变为:

    a[i]_address = first_address + (i-1) * data_size
    

    从 1 开始编号,每次随机访问数组元素都多了一次减法运算,对于 CPU 来说,就是多了一次减法指令。

    数组作为非常基础的数据结构,通过下标随机访问数组元素又是其非常基础的编程操作,效率的优化就要尽可能做到极致。所以为了减少一次减法操作,数组选择了从 0 开始编号,而不是从 1 开始。

    展开全文
  • 数组的下标为什么从0开始而不是从1开始

    万次阅读 多人点赞 2020-02-25 18:45:56
    如果从0开始,则a[i]的地址= 首地址 + i*每个数据所占的长度; 如果1开始,则a[i]的地址= 首地址 + (i-1)*每个数据所占的长度。 是不是前一种更好计算呢。 再举个例子: 1、数组在内存中申请是,所申请的内存是一段...

    数组是一段连续的空间,要求a[i]就是求它的地址,然后找到它。
    在这里插入图片描述

    如果从0开始,则a[i]的地址= 首地址 + i*每个数据所占的长度;
    如果从1开始,则a[i]的地址= 首地址 + (i-1)*每个数据所占的长度。
    是不是前一种更好计算呢。

    再举个例子:
    1、数组在内存中申请是,所申请的内存是一段连续的内存地址;
    2、例:int[] a=new int[3];申请一段:int 数据类型的数组,a 为变量,数组长度为:[3];
    3、这个数组所申请的内存地址是连续的
    (假设所申请的:第一个内存地址为:1008,第二个为:1009,第三个为:1010);
    但我们只知道:一、变量:a,它只拿到第一个内存地址1008;二、它的数组空间为3个;
    4、a[0]——把a拿到的内存地址:1008 + 0 = 1008 (指向第一个内存地址);
    a[1]——把a拿到的内存地址:1008 + 1 = 1009 (指向第二个内存地址);
    a[2]——把a拿到的内存地址:1008 + 2 = 1010 (指向第三个内存地址);
    所以:数据下标从 [0] 开始的意义也在于此!(当然,这是理解版的)。
    (备注):如果你写a[3],它就报错了,越界错误,因为你只申请了3个内存空间。

    展开全文
  • 数组下标索引为什么从0开始

    千次阅读 2020-08-17 21:26:17
    C语言数组下标是从0开始->Java也是->JavaScript也是。 降低额外的学习和理解成本。 原因二:减少CPU指令运算 (1)下标从0开始数组寻址——arr[i] = base_address + i * type_size 其中base_address...

    也不是所有的高级程序语言都是如此,比如Python数组下标就支持负数。

    原因一:历史原因

    语言出现顺序从早到晚C、Java、JavaScript。
    C语言数组下标是从0开始->Java也是->JavaScript也是。
    降低额外的学习和理解成本。

    原因二:减少CPU指令运算

    (1)下标从0开始:

    数组寻址——arr[i] = base_address + i * type_size

    其中base_address为数组arr首地址,arr[0]就是偏移量为0的数组,即数组arr首地址;i为偏移量,type_size为数组类型字节数,比如int为32位,即4个字节。

    (2)下标从1开始:

    数组寻址——arr[i] = base_address + (i -1)* type_size

    比较两个计算公式可以发现公式(2)每次CPU寻址需要多一次 i-1的操作,即多了一次减法的指令运算。

    对于数组这种基础数据结构,无论在哪种高级程序语言中,都是频繁间接(作为容器的基础数据结构,比如Java的ArrayList)或者直接被使用的,因此要尽量减少其消耗CPU资源。

    原因三:物理内存的地址是从0开始的

    计算机主存是多个连续字节大小的单元组成的数组,每个字节都对应唯一的物理地址,第一个字节的地址为0。

    展开全文
  • 1 为什么很多编程语言中数组都是 0 开始编号 1.1 效率原因 1.2 历史原因 2 数组的特点 2.1 随机访问 2.2 低效的“插入”和“删除” 2.2.1 低效原因 2.2.2 改进方法 3 数组越界问题 4 容器和数组用哪个更好 ...

    正文

    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[9]

    看内存情况我们得到:

    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。

    那什么时候用数组,什么适合用容器呢?

    容器的优势就是可以将很多数组操作的细节封装起来,有的还支持动态扩容。

    王争老师:如果特别关注性能,或者数据大小已知,且对数据操作非常简单,用不到容器提供的大部分方法,可以是用数组。


    完,不足之处请指正。

    展开全文
  • 也不是所有的高级程序语言都是如此,比如Python数组下标就支持负数。
  • 在大部分编程语言中,数组都是从0开始编号的,但你是否下意识想过,为什么数组从0开始编号,而不是1开始呢? 1开始不是更符合人类的思维习惯吗?下面以这个问题来学习数组。 如何实现随机访问? 什么是数组?...
  • 为什么数组从0开始

    千次阅读 2014-06-07 21:56:20
    为什么C语言的数组从开始呢?
  • 计算机数组索引为什么从0开始

    千次阅读 2020-01-07 12:00:41
    参考 数据的存储 一字节 8bit 链表,查找地址,针对于起始地址的偏移量
  • C++/JAVA 的数组下标为什么从0开始

    千次阅读 2017-12-05 10:38:52
    在我们日常的学习过程中,我们了解到在C++/JAVA中,数组下标是从0开始的。对于新手来说,遍历的数组的时候还真是容易出错。但是为什么要这样规定,这样规定有什么好处? 其实根据我们前辈的思想,这样规定的主要...
  • 数据结构 – 数组 概念 数组是一种线性表数据的结构,他用一组连续的内存空间,来存储一组相同数据类型的数据。 线性表:数据排列成一条线一样的结构。数据结构特点:存在一个唯一的没有前驱的(头)数据元素;存在一...
  • 数组下标为什么从0开始:a.初步理解:b.加深理解: 1.数组的由来: // 变量声明 int a = 1; int b = 2; int c = 3; int d = 4; ... int n = 20; // 一个int类型4个字节,一个字节占8位 a.字面引申: ...
  • 数组下标为什么从0开始

    千次阅读 2017-08-30 10:49:08
    为什么从0开始计呢? int[] a=new int[]{1,2,3,4,5};   这里有5个值,首先我们假设数组在内存中开辟的5个地址号为1000,1001,1002,1003,1004,假设是为了方便计算。 此刻我们访问a[0],也就是访问到地址...
  • 假设有个数组int a[10],它的起始地址值0x1000(address),那么当你访问第n个数据时(即a[n]),实际上是通过其地址值获取对应位置的数据访问,如下图: 其寻址公式:result = address + 4 * n(4代表数据类型...
  • 数组的下标,为什么从0开始

    万次阅读 2018-10-18 09:13:52
    为什么数组的下标是从0开始,而不是1开始呢?1开始不是更符合人们的习惯么。 这个问题,稍后回答,先聊聊数组的基本特性。 数组(Array)一种线性表数据结构,用一组连续的内存空间,存储一组相同类型的数据 ...
  • 数组的下标为什么从0开始

    千次阅读 2019-01-12 14:11:34
    数组(Arrary)是一种线性表数据...如果用a来表示数组的首地址,a[0]就是偏移为0的位置,也就是首地址,a[k]就表示偏移k个type_size的位置,所以计算a[k]的内存地址只需要用公式: a[k]_address = base_address ...
  • 对于学习过编程语言的人来说,相信绝大多数人都会有这样的疑问:我们平时计数,通常是一开始计数的,为什么在编程语言中,数组的下标是从0开始计算的呢?  这是因为,C语言中,下标的含意是:当前元素到第一个...
  • 数组下标为什么从0开始

    千次阅读 2013-11-08 21:47:19
    从0开始的话,只需用数组名(也就是数组地址),加上下标,只需要很简单的计算,就可以内存中准确访问到元素。 -------------------------------------------------------- 像在pascal这样的语言中,数组下标是可由...
  • PHP 多维数组将下标从0开始

    千次阅读 2018-03-16 17:13:12
    点击链接加入群【php/web 学习课堂】:https://jq.qq.com/?_wv=1027&k=5645xiw 欢迎大家加入,一起讨论学习 ... //自定义一个数组,模拟成在数据库里提取出来的 $array = [ '2018-3-2'=>
  • 数组下标从0开始

    千次阅读 2016-06-21 16:19:20
    数组下标 偏移量
  • C语言数组元素下标为何从0开始

    万次阅读 多人点赞 2016-05-06 11:24:51
    很多同学可能在学习数组时会有这个疑问,下标为什么1开始呢?1开始不是更符合大家的日常习惯吗?生活中我们通常说第1个,而不是第0个。的确,有些计算机语言如早期的Pascal语言,数组元素的下标是1开始的。...
  • 先说说为什么C语言的数组从0开始:众所周知,C语言的数组是直接操作内存,那我们肯定得内存的寻址开始说起,以“以行为主序”的分配为例:设数组的基址为LOC(a c1 c2),每个数组元素占据l 个地址单元,那么...
  • 曾经有人在Twitter上问我为什么Python使用以0为首位的数组索引法(0-based),并且还给我了一个相关优秀文章的链接。这让我想起许多往事:Python的前身之一,ABC语言使用的是以1为首位的数组索引方式(1-based),而对...
  • C语言数组下标为何从0开始

    千次阅读 2007-11-07 14:06:00
    Many other features, besides the type system, were put in C for the C compiler-writer'... java为何下标也从0开始呢,估计是考虑到习惯性问题.C/C++程序员被固化成下标从0开始后,想更改它也是件费劲事.  
  • 大家学习c语言刚接触数组时候,书上说第一个数组元素要下标0开始数起,不能1开始数,比如 int a[4]={1,2,3,4}; 那么a[0]=1; 为什么1数起呢 即a{1}=1呢?不更符合大家的生活习惯吗?
  • 数组看起来简单基础,但是很多人没有理解这个数据结构的精髓。 数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。 //个人思考: 数组即线性表中的顺序表,...
  • 特殊矩阵的压缩存储(数组下标从0开始存储)

    千次阅读 多人点赞 2019-01-05 15:15:51
    用一维数组压缩存储 对称矩阵 对称矩阵的特点: a[i][j] = a[j][i] ...a[0][0] 开始,把每行元素都依次存储进一维数组 存储时:a[i][j] 在一维数组 A[ ]中的下标就是该元素前面元素的个数:k= i×(...
  • php 二维数组key初始化从0开始

    千次阅读 2018-04-10 11:17:00
    这个是一个二维数组 array(2) { [1]=> array(2) { ["sourcesid"]=> int(1) ["addusernum"]=> string(1) "4" } [6]=> array(2) { ["sourcesid"]=> ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,379,615
精华内容 551,846
关键字:

数组为什么从0开始