V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
drymonfidelia
V2EX  ›  程序员

为什么除了 lua,数组索引基本都从 0 开始?很反人类的设计,很容易写出 bug

  •  
  •   drymonfidelia · 278 天前 · 12334 次点击
    这是一个创建于 278 天前的主题,其中的信息可能已经有所发展或是发生改变。
    105 条回复    2024-05-02 20:39:03 +08:00
    1  2  
    wolfie
        1
    wolfie  
       278 天前   ❤️ 3
    使用另一个语言时候,就要做一定妥协。
    0 代表 偏移量为 0 ,没什么问题啊。
    Adelell
        2
    Adelell  
       278 天前 via iPhone   ❤️ 15
    碳基喜欢数数从一开始,硅基喜欢从零开始。
    mohumohu
        3
    mohumohu  
       278 天前
    也有好处,比如你循环 100 次可以直接写小于 100
    ipwx
        4
    ipwx  
       278 天前
    你可以申请 N+1 个大小,然后扔掉第 0 个。。。
    drymonfidelia
        5
    drymonfidelia  
    OP
       278 天前
    @ipwx 那样解析 json 或者其它外部来源的数组的时候就会丢掉一个
    ipwx
        6
    ipwx  
       278 天前   ❤️ 1
    都处理 JSON 的代码了,世界上大部分语言都是 0 开始的,或许你需要修正一下自己的习惯
    kneo
        7
    kneo  
       278 天前 via Android   ❤️ 5
    为什么有的语言和别人都不一样,就没想过反思一下吗?
    但凡写过一千行正经代码都不会说出这种标题。
    yunye
        8
    yunye  
       278 天前   ❤️ 5
    你不喜欢就说你不喜欢,别轻易代表人类
    stinkytofu
        9
    stinkytofu  
       278 天前   ❤️ 1
    我们日常生活中很多都是从 0 开始的。 比如最常用的时间,0 点就是一天的开始
    drymonfidelia
        10
    drymonfidelia  
    OP
       278 天前
    @kneo 我写过几十万行了
    YsHaNg
        11
    YsHaNg  
       278 天前
    nuistzhou
        12
    nuistzhou  
       278 天前 via iPhone
    哈哈,你再看看那些有 0 层的电梯
    kneo
        13
    kneo  
       278 天前 via Android   ❤️ 14
    @drymonfidelia 我说的是正经代码。你这几十万怎么来的我不知道。但我不相信一个手动敲过千行代码,写过循环,用过数组,修过 bug ,认真思考总结过的人,能问出这种不正经的问题。
    country
        14
    country  
       278 天前
    因为《爱从零开始》
    drymonfidelia
        15
    drymonfidelia  
    OP
       278 天前
    @kneo 我随便写着玩的一个抢购脚本都不止千行
    dobelee
        16
    dobelee  
       278 天前 via Android   ❤️ 1
    “容易出 bug”是怎么得出的?工作中从来没有因为 0 出过 bug ,也没有见过人因 0 出过 bug 。只有初学几天的由于习惯问题别扭。
    BeautifulSoap
        17
    BeautifulSoap  
       278 天前 via Android   ❤️ 41
    楼上这么多人甚至都没人回答到点的,你们不会连 c 都没学过吧。。。

    但凡学过 c 这类底层点的语言也不会问出这种问题。。。

    因为数组本质上是一个指向一整块连续内存块的指针(即存储了一块内存的地址),访问数组元素本质上就是对指针做加法操作。
    比如数组 a 指向的内存块地址是以 0x0001 为起点的一块连续内存,这样 0x0001 这个位置的数据就是第一个元素。要取第一个元素的话就直接获取 0x0001 + 0 处的元素,要获取第二个元素的话就是去获取 0x0001+4*1 这个地址下的数据(假设这个数组是存储了 32bit 共 4 自己长度的 int 元素的数组),获取第三个元素就是 0x0001+4*2 。就这么简单的理由,数组中下标指代的就是*1 *2 这里的数字,本质上就是一个“语法唐”

    至于其他语言里“数组”可能并非真数组,可变长度的“数组”并非原始严格意义上的数组。但是为了保持一直以来的使用习惯,也采用了一模一样的下标用法
    heiher
        18
    heiher  
       278 天前 via Android   ❤️ 1
    个人拙见应该只是为了简化内存系统地址计算与编程语言层面的数组索引的映射关系。比如有一个数组包含 2 个字节单位的元素,存放于内存中,内存起始地址是 A ,那么第 1 个字节的内存地址就是 A(+0),第二个是 A+1 ,即映射算法就是 A+index 。编程语言若将数组索引设计为从 0 开始能刚好匹配,而如果编程语言索引是设计从 1 开始的,那么数组访问转换到内存寻址算法则是 A+index-1 。人看着可能是自然了,但在当前主流的 CPU 指令系统上,变量 index 的场景要多一步-1 的运算吧。
    cxumol
        19
    cxumol  
       278 天前
    错误的, R 语言也是从 1 开始数起
    lesismal
        20
    lesismal  
       278 天前
    学代码之前数数可从来没从 0 开始过啊...
    学代码之时觉得从 0 开始咋这么反人类...
    学代码之后觉得从 1 开始咋这么反人类...
    LeeReamond
        21
    LeeReamond  
       278 天前   ❤️ 7
    @drymonfidelia 我从高中码到现在超过十年,仔细想了一下我个人实践的所有项目,恐怕加在一起也就二十万到三十万行之间,而且我自觉算是很勤奋的了。企业里正常程序员计算绩效,别管用什么语言,一天提交超过 200 行就算满状态工作了,算下来你十年不停,总共也就能开发 70 万行代码。

    不知道你这几十万怎么出来的,几十万哥问出内存计数问题属实是让人见识物种多样性了。
    hello2090
        22
    hello2090  
       278 天前 via iPhone   ❤️ 1
    @drymonfidelia 所以是写了几十万行还经常数组 0 ,1 搞错?经常用[1]取第一个元素还是用[a.length]取最后一个元素?
    nagisaushio
        23
    nagisaushio  
       278 天前 via Android
    pascal: 你好
    xiaogeformax
        24
    xiaogeformax  
       278 天前
    有需求可以改 lua 源码的,可以改成索引 0 开始
    ARCHOR
        25
    ARCHOR  
       278 天前
    脑内编译确实反人类 hhh
    snw
        26
    snw  
       278 天前 via Android
    Excel 欢迎你,单元格坐标和公式都是从 1 开始数,VBA 甚至能自行指定下标从 1 开始还是从 0 开始 🐶
    Helsing
        27
    Helsing  
       278 天前 via iPhone   ❤️ 2
    @heiher #18
    步骤是一样的,不过从 0 开始通过加法就可以得到内存地址,从 1 开始要通过减法,但是加法的指令要比减法的指令快得多,所以设计成从 0 开始,对于提升底层效率是非常有用的,这个也是这样设计的最主要原因 @drymonfidelia
    ShuWei
        28
    ShuWei  
       278 天前
    多写代码少抱怨,如果你是 Linus Torvalds 之流,随便喷,喷完还有人听,如果不是,遵守规则对自己比较好

    至于因为 0 开始容易写 bug ,这还是代码写少了而已,多写写就好了
    shinsekai
        29
    shinsekai  
       278 天前
    错误的,MATLAB 也是从 1 开始
    iOCZS
        30
    iOCZS  
       278 天前
    下标是数组地址的偏移啊,第一个当然是 0 偏移
    cmdOptionKana
        31
    cmdOptionKana  
       278 天前   ❤️ 3
    编程、数学、物理学之类的纯理性的东西,本来就是反人类的,更严谨的说法是,这些学科不太关心“人类”,而是更关心“本质”。

    编程,最初是让人去服务电脑,因为当时电脑的能力有限,人(程序员)要牺牲自己去迁就电脑,从 0 开始算是一种历史遗留习惯吧,其实以现在的电脑能力来看,从 1 开始完全没问题,只是这本身影响不大,就懒得改一直沿用下来了。
    hertzry
        32
    hertzry  
       278 天前
    错误的,Wolfram 也是从 1 开始。
    Pteromyini
        33
    Pteromyini  
       278 天前
    我的理解是,多数语言数组标识表示的是偏移量,也就是从起始内存+偏移量*固定位宽。所以第一个偏移量是 0 ,即从 0 开始
    Building
        34
    Building  
       278 天前
    你可以自己封装一个数组 wrapper ,从 1 开始,就是和别人合作容易被打
    foam
        35
    foam  
       278 天前 via Android
    @mohumohu 从 1 开始,也可以直接写 <=100 。其实都不是问题
    iseki
        36
    iseki  
       278 天前 via Android
    可能是因为他们想用这个数字表示 offset 吧,那开头的那个 offset 可不就是 0 呗。如果你的程序也是按 offset 这套思路走,那还是挺舒服的。
    iseki
        37
    iseki  
       278 天前 via Android
    @foam 其实还有个事,index 往往是个 i 或者 ui ,从 1 开始就浪费一个
    iseki
        38
    iseki  
       278 天前 via Android
    早期语言很多都不是从 0 开始的,可能 C 开了个头?人家有指针,按 offset 的思路走很正常
    baobao1270
        39
    baobao1270  
       278 天前 via Android
    因为编程语言最开始是 C ,用指针(指向一段内存的开头)来计数
    日常计数中,我们说的 1 2 3 4 其实是指代 0~1 1~2 2~3 3~4 这样的区间 也就是用结尾指代第 n 个区间
    编程语言的计数是用开头指代第 n 个区间
    从科学的角度看,日常语言才是奇怪的那个
    newtype0092
        40
    newtype0092  
       278 天前   ❤️ 1
    我以为是说 lua 从 1 开始反人类,没想到。。。这种思想不是从刚学编程时就会被扳过来么。
    sunfall
        41
    sunfall  
       278 天前
    @newtype0092 看到这才发觉问的从 0 开始反人类
    akira
        42
    akira  
       278 天前
    pascal 和 delphi 已经没人提了么。。
    howieyoung91
        43
    howieyoung91  
       278 天前
    0 是指偏移量,并不是第 0 个、第 1 个这种意思
    roc1415926816
        44
    roc1415926816  
       278 天前
    自然数不就是从 0 开始的吗。
    你用的尺子的时候刻度也是从 0 开始的。
    fyxtc
        45
    fyxtc  
       278 天前
    反你=反人类,但凡 cs 过了第一年都不会问出这种问题。
    只会用🔨然后上工人论坛大呼其他工具反人类,说🔧🪛这些很容易弄伤手。
    phoulx
        46
    phoulx  
       278 天前
    建议复习(预习?) Dijkstra 的文章:Why numbering should start at zero
    https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html
    yanyao233
        47
    yanyao233  
       278 天前 via Android
    从没因为这个写出过 bug ,我觉得这种问题更多应该从自身找问题
    deplives
        48
    deplives  
       278 天前
    反思反思,写了几十万行代码还能问出这个问题。哦,有可能你的几十万都是 lua ,脚本小子。
    lyer5
        49
    lyer5  
       278 天前
    为什么感觉索引从 1 开始才是反人类,不习惯😂
    tonytonychopper
        50
    tonytonychopper  
       278 天前
    除非是新手不然很难出错吧
    cmdOptionKana
        51
    cmdOptionKana  
       278 天前   ❤️ 1
    @roc1415926816 自然数是否从 0 开始其实也不是很“自然”,有过争论和修改。

    “2000 年左右之前的中小学教材一般不将 0 列入自然数之内。在 2000 年左右之后的新版中小学教材中,普遍将 0 列入自然数”(摘自维基百科)
    julyclyde
        52
    julyclyde  
       278 天前
    @nuistzhou 只听说过 G 层电梯;还有零层的吗?
    wangxiaoer
        53
    wangxiaoer  
       278 天前
    别扯淡了,随便去大街上拉个人,把你是个手指头伸出去,问他第一个是第几个,你看看有几个说 0 的。

    楼上有些说尺子、时钟的,这些都是指的某一刻,而数组第 n 个元素很显然不是某个刻度,而是某两个刻度之间的那个元素。 如果类比为尺子、时钟,正常人肯定也会认为 第一段、第一个小时更符合直觉。

    这个下标从零开始楼上已经解释清楚了,后来就约定俗成大家都这么做了,但并不意味这就是真理,不同的编程语言设计者可以凭自己喜好选择不同的方案,不存在啥对错之分。
    gpt5
        54
    gpt5  
       278 天前 via iPhone
    Matlab 也是从 1 开始
    adoal
        55
    adoal  
       278 天前
    从几开始都是浮云。甚至有的语言可以自由定义数组实例的上下标范围。
    相对于下标开始的数值来说,更有讨论意义的是,表示一段离散区间时,结束位置用 inclusive 还是 exclusive 。
    roundgis
        56
    roundgis  
       278 天前 via Android
    自从 C 系语言统治编程界后就很少听到这种言论了
    falcon05
        57
    falcon05  
       278 天前 via iPhone
    只是语言设计者偏好,跟喜欢某种东西的颜色一样,至于说非要写一千行代码才能理解的说法,纯属放 tm 的狗屁。
    roundgis
        58
    roundgis  
       278 天前 via Android
    @julyclyde 我现在住的地方 G 在电梯就是 0 层

    停车场是-1 -2
    cmdOptionKana
        59
    cmdOptionKana  
       278 天前   ❤️ 1
    @wangxiaoer 看大家的讨论,可以发现,人类为了维护自己的习惯或选择,会强行赋予“正确性”甚至“神圣性”,很有趣也很常见的心理现象。

    这也让我想另一件趣事,起很多人对“独立思考”的理解是:不受外界的影响,坚持自己最初的想法,不要被人改变想法,主要集中于思考如何维护自己的正确性。

    但独立思考其实应该是反思,主要思考自己可能是错的,要对自己最初的想法进行“拷打”,看它能不能经受住质疑,一旦发现逻辑有问题就要敢于改变或修正自己的想法。
    julyclyde
        60
    julyclyde  
       278 天前
    @roundgis 按钮上写的是零层吗?好厉害!
    Inn0Vat10n
        61
    Inn0Vat10n  
       278 天前
    不是从 C 开始学的程序员,可能体会不到内存/pointer 操作时这个 1 ,0 差异带来的便利性
    kkocdko
        62
    kkocdko  
       278 天前   ❤️ 2
    @BeautifulSoap 一楼就已经“回答到点上”了,似乎你也没注意看呢
    cnbatch
        63
    cnbatch  
       278 天前
    @roundgis 啊哈,英式楼层编号方式,地面是第 0 层
    BeautifulSoap
        64
    BeautifulSoap  
       278 天前
    @kkocdko “偏移量”无法解释为什么从 0 开始的哦。因为在普通人朴素的认识里,第一个元素的偏移量那就是 1
    fkdog
        65
    fkdog  
       278 天前
    C 语言里数组变量指针指向的就是第一个元素的地址。
    那取第一个元素就直接 a[0],取第一个元素就是 a[1]
    laminux29
        66
    laminux29  
       278 天前
    1.楼主说得对,这是计算机发展历史上的遗留问题,诸如此类问题,其实还有很多,比如,你去菜鸟驿站发邮件,发件方与收货方的地址,会写 1.2.3.4 和 5.6.7.8 嘛?

    2.楼上很多学过的人,居然为这事强行洗。学习知识是为了用它、打破它,而不是被它固化与束缚。
    snw
        67
    snw  
       278 天前 via Android
    说到楼层的话,那可就不止 0 层/G 层了。。。

    meislinsen
        68
    meislinsen  
       278 天前
    lua 语言才是真正反人类的语言,其他语言都是从 0 开始,就 lua 非要从 1 开始,从其他语言转过来就很适应,而且从 1 开始并没有什么特殊的理由,只是创始人的怪癖和标新立异,人为给 lua 语言和其他语言转换的困难。然后 lua 语言的表结构也很逆天,综合了字典和数组的功能,但是#只能取数组的长度,要取字典的还得自己实现,
    adoal
        69
    adoal  
       278 天前
    @BeautifulSoap offset 是相对于 base 而言的。0 表示距离 base 为 0 ,1 表示距离 base 为 1……如果 head 元素偏移量是 1 ,那 base 是谁?在 head 之前强行引入一个 pre-head 作为 base ?
    普通人意识里的从 1 开始,不是 offset ,而是 ordinal
    adoal
        70
    adoal  
       278 天前   ❤️ 1
    如果你执着于把最开始的元素称为“第一个”,那就会在这事上纠结死。称为“头部”即可不在乎人类的序号规则,平心静气接受用元素距离头部的偏移量作为索引。
    adoal
        71
    adoal  
       278 天前
    另外我想说的是,如果用下标从 0 开始的语言你容易写出 bug 来,换成下标从 1 开始的语言你一定还是会写出同样的 bug 。
    locoz
        72
    locoz  
       278 天前
    @drymonfidelia #15 抢购脚本行数多不是很正常吗...如果是直接控制浏览器做的,光获取元素的都会有一堆内容,但那都是操作逻辑,跟编程语言的底层逻辑关系又不大,拿这个举例不太合适。
    rahuahua
        73
    rahuahua  
       278 天前
    @BeautifulSoap 你说的这么多和一楼说的有什么区别,这不是学过编程的都知道么
    NX2023
        74
    NX2023  
       278 天前
    唔除了 Lua ,MATLAB 也是从 1 开始的(((
    BeautifulSoap
        75
    BeautifulSoap  
       278 天前 via Android
    @adoal 不需要你来给我解释,问一下身边没学过编程的人,他们下意识会认为偏移应该从 0 开始还是 1 开始


    @rahuahua @adoal
    “这不是学过编程的都知道的吗”
    典型的知识的诅咒一般的言论。lz 写了这么多年代码依旧无法理解为什么数组从 0 开始,你真觉得我不把最底层内存地址的计算方法给说给 lz 听,他真能理解所谓的偏移量是什么东西吗
    inertia
        76
    inertia  
       278 天前
    Julia 也是从 1 开始的,Fortran 、Mathematica 和 MATLAB 也一样。科学计算语言应该大部分都是从 1 开始的。
    adoal
        77
    adoal  
       278 天前   ❤️ 1
    @BeautifulSoap 不不不,他们认为的“事”跟“偏移量”根本无关。你说的““偏移量”无法解释为什么从 0 开始的哦”,首先真的是要来谈偏移量,在编程这个语境里,然后再谈认知从 0 还是从 1 开始的合理性。而真正的普通人,他们说的只是“数(上声)数(去声)时的编号从 1 开始”,他们甚至脑子里嘴里都没有出现偏移量这个概念,你问他(编程,或者非编程时排列在一起的同质物品中的)一个元素相对于首位的偏移量是从 0 还是 1 算,他第一反应你说的是什么鬼东西。

    另外我还想说的是,如果写了多年代码,并且从 0 和从 1 开始的语言都正式使用过,那不论是认为 0“更”合理还是 1“更”合理都没问题,但这里的出发点是“更”,也就是说至少对两种方式的优缺点都有所体会,对各自的合理性都能认识到,然后再这个基础上再谈自己的倾向性。而不是依旧无法理解其中一种方式的合理性,只认为另一种合理。多年下来还理解不了的,恕我暴论,还是别做程序员了吧。
    zhady009
        78
    zhady009  
       278 天前
    入乡随俗怎么样我都行(
    raptor
        79
    raptor  
       278 天前
    看来你没用过 Pascal 。

    想当年我一手 C 一手 Pascal ,一点问题都没有
    iyaozhen
        80
    iyaozhen  
       278 天前
    很反人类的设计 或许吧

    很容易写出 bug ,这不认同。没见过这种 bug
    ZIXT
        81
    ZIXT  
       277 天前   ❤️ 1
    感觉可以这么解释:
    如果是数数,用 1 开头确实是自然的,因为“0 个”对应的是不存在,(最早数数的人类)自然不会用"第 0 个"指代某个存在的实体;
    但当遇到“定位”的场合,举个例子:坐标轴,其原点一般都表示为(0,0),因为这里的 0 代表的是距离的数值,也就是偏移。而计算机寻址恰恰就是这种需要“定位”的场合(基址+偏移),而数组也是基于“定位“的思想而不是数数的思想设计的,所以数组的头部元素为[0]
    maigebaoer
        82
    maigebaoer  
       277 天前 via Android
    这个问题很经典,Google 搜下英文,🈶详细说明。
    cccer
        83
    cccer  
       277 天前
    因为自然数就是从 0 开始,从 0 开始才是更合理的。
    leonshaw
        84
    leonshaw  
       277 天前 via Android   ❤️ 1
    @maigebaoer 这个,Dijkstra 的 Why numbering should start at zero
    https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html
    cccer
        85
    cccer  
       277 天前
    再者编程语言由二进制机器码发展而来,0 和 1 组成,自然而然是从 0 开始计数。
    ttvast
        86
    ttvast  
       277 天前 via Android
    不从 0 开始计数已经为人类生活带来了很多麻烦了,所以计算机语言里用 0 做第一个下标的做法是很有智慧的。
    1 走到 6 层楼楼梯阶数并不是走到 3 层楼的两倍
    2 公元一年和公元前一年只相差 1 年,而不是 2 年
    DIO
        87
    DIO  
       277 天前
    计算机底层思维是这样,硬件 0 就是地址 0 。
    YsHaNg
        88
    YsHaNg  
       277 天前 via iPhone
    @julyclyde 英国电梯按钮写 0 和 g 的都有 但肯定没有直接从 1 开始的
    James369
        89
    James369  
       277 天前
    为了方便程序逻辑,特别是 C 语言的内存地址操作
    memorycancel
        90
    memorycancel  
       277 天前
    看了一下 17 楼 喷到点子上了- -
    Jirajine
        91
    Jirajine  
       277 天前   ❤️ 1
    @BeautifulSoap #17 你这样你说反倒体现了 0 index 的问题所在,array 本身被模糊和滥用了。
    memory chunk 和 collection 是两种 sematic,他们俩不应该共用同一种 syntax ,也就是不应该把 p.offset(a) 和 p.index(a)都共用 p[a]。
    boatrain1111
        92
    boatrain1111  
       277 天前
    我觉得从 0.5 开始最好
    shuax
        93
    shuax  
       277 天前
    matlab:你好
    vincent7245
        94
    vincent7245  
       277 天前
    我想起了好多年前的一个下午,关于大端和小端的激烈讨论
    MoYi123
        95
    MoYi123  
       277 天前
    dijkstra 关于这个写过文章, 可以看看.
    https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html
    myderr
        96
    myderr  
       277 天前
    错误的,E 也是从 1 开始。
    wanguorui123
        97
    wanguorui123  
       277 天前
    在计算机里 0 是有意义的,0 既然被存储,那就不能被浪费,所以从 0 开始最省空间和计算资源
    whyso
        98
    whyso  
       277 天前
    说归说,别动不动就反人类,你能代表谁啊?
    lawlyet666
        99
    lawlyet666  
       277 天前
    哈哈哈,"几十万哥"
    126ium
        100
    126ium  
       277 天前 via Android
    @hello2090 可能他外包干太多?
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5143 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 09:36 · PVG 17:36 · LAX 01:36 · JFK 04:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.