Skip to content
DevMeme

The Holy War of Array Indexing: 1-based Order vs. 0-based Chaos — Meme Explained

The Holy War of Array Indexing: 1-based Order vs. 0-based Chaos
View this meme on DevMeme →

Level 1: Counting from Zero

Imagine you and a friend are going to visit someone in a building. Your friend is from a country where they label the ground floor as 0 and the floor above it as 1. But you’re used to calling the ground floor 1 and the next one 2 (like in many US buildings). Now suppose you agree to meet on the “1st floor.” You show up at what you call the 1st floor (ground level), but your friend goes to what they call the 1st floor (one level above ground). You end up on different floors, all because you started counting floors differently!

This is just like the array joke in the meme. One group thinks the first item should be numbered 1 (like calling the ground floor the 1st floor), and the other group thinks it should be numbered 0 (calling the ground floor 0 and the next one 1). Neither way is “wrong” by itself – they’re just different conventions. But if you mix them up, you can get pretty confused or lost. The people in the top part of the comic are calmly using the simple, everyday way of counting (1, 2, 3,...), and the folks in the bottom part are using the zero-start way and bending themselves into knots explaining it (kind of like someone insistently explaining “the ground floor is floor 0!” to someone who’s never heard that before).

The reason this is funny to programmers is that we’ve all had little mishaps because of this counting difference. It’s a bit like forgetting which way to count in the building and ending up one floor off – just as you and your friend missed each other by one floor. The phrase "Holywar... holywar never changes" in the caption jokes about how this silly argument about where to start counting (0 or 1) has been going on forever among computer folks, with no one ever really “winning” it. In the end, the lesson is simple: whether you start at zero or one, just be clear and consistent – otherwise you might end up on the wrong floor (or looking for the wrong array element)!

Level 2: Counting Confusion

Let’s break this down in simpler terms. An array is just an ordered list of items (numbers, words, etc.) where each item can be accessed by a number called an index. The big question (and the source of the joke) is: do we start that index at 0 or at 1?

  • 1-based indexing means the first element of the array is index 1, the second element is index 2, and so on. For example, if we had a list of students, we might say student 1 is Alice, student 2 is Bob, etc. This feels natural because it’s how we normally count things in everyday life.
  • 0-based indexing means the first element of the array is index 0, the second element is index 1, etc. In the same list of students, Alice would be at index 0 and Bob at index 1. That means the n-th student ends up at index n-1. So a list of 5 students uses indices 0,1,2,3,4 for the 1st through 5th students respectively.

Different programming languages choose different default indexing strategies. Most modern languages like C, Java, Python, and JavaScript use 0-based indexing. Some languages and tools more geared towards math or statistics, like MATLAB or R, use 1-based indexing to match how mathematicians typically enumerate items. This difference is a common language quirk that can surprise newcomers. If your first programming language was Python (0-based) and then you try MATLAB, you might wonder why MATLAB throws an error when you try to access index 0 of an array (because it expects indices to start at 1!). Conversely, someone who learned in a 1-based environment often initially gets errors in a 0-based language by trying to use an index that is one too high.

Here’s an example in a 0-based indexing setting (using a Python-like pseudocode):

numbers = [10, 20, 30, 40, 50]  # a list with 5 elements
print(numbers[0])  # outputs 10, this is the 1st element (at index 0)
print(numbers[4])  # outputs 50, this is the 5th element (at index 4)
print(numbers[5])  # Error! There's no index 5 in a 5-element list (indices go 0-4)

In this list, numbers[0] gives the first element (10). If you try numbers[5], you get an error because you’re essentially asking for a "sixth" element that doesn’t exist. In a 1-based system, that same list of 5 elements would have indices 1 through 5, and asking for the 5th element would be valid (it would give 50). But you would never ask for index 0 in a 1-based system – that would be nonsense or an error.

Now, why do many languages use 0-based indexing? One reason is how arrays are laid out in memory. Think of an array like a row of mailboxes, and you have the address of the very first mailbox. If you want the first mailbox, you go to that starting address (no offset needed). If you want the second mailbox, you go a bit further down the row by one mailbox’s length. In computing terms, the index is used as an offset from the start address of the array. Using 0 for the first element means "no offset from the start". Using 1 for the first element would mean there’s an implicit offset of one unit that you always have to account for. In languages like C, this is exactly how it works under the hood: array[index] is basically “start at the beginning of the array and move index positions over.” So if index is 0, you don't move at all – you’re at the first element. If index is 1, you move one element over – that’s the second element, and so on. This is what we mean by pointer arithmetic or using memory offsets.

Another reason often cited (as in one of the meme’s speech bubbles) involves using the modulus operator (written %) to wrap around indices. The modulus gives the remainder after division, and it’s handy for making an index “wrap around” when it goes out of bounds. In a 0-based system, if you have an index and you do index % N (for an array of size N), the result will naturally fall between 0 and N-1, which are exactly the valid index range. For example, say you want to cycle through a list of 5 items in a loop. If you go past the last index, you can do next_index = (current_index + 1) % 5 to wrap around. If current_index was 4 (the last index), 4 + 1 = 5 and 5 % 5 = 0, which neatly brings you back to index 0 (the start of the list). If your indexing was 1-based (indices 1 to 5), the math to wrap around becomes a little more awkward: you might do next_index = (index % 5) + 1, to ensure the result falls between 1 and 5. It’s a small difference in code, but programmers appreciate when these little things line up nicely without extra adjustments.

Now, what about the meme’s line “the second element is the first element. the first is the zeroth”? This is highlighting how zero-based indexing can be counter-intuitive in plain language. If someone says “the second element”, a person might naturally think that’s index 2. But in a zero-based world, “the second element” is at index 1 (because we started counting at 0 for the first). Similarly, “the first element” is at index 0 (programmers often jokingly call it the "zeroth element"). That can sound very confusing if you’re not used to it – almost like a who’s-on-first comedy bit. The meme shows the zero-index folks kind of tangled up because they have to twist their language and thinking to explain this concept.

Finally, what is an off-by-one error? This term describes a very common bug where a programmer is off by one in a count or index, usually by using the wrong starting point or wrong end point. It often happens when someone loops through an array and accidentally goes one step too far or one step short. For example, imagine you have 10 items and you write a loop that runs 11 times by mistake – that extra iteration is an off-by-one error. Or if you have a 5-element array and you try to access index 5 (thinking you’re getting the 5th element), that’s an off-by-one mistake because the last index should be 4. These mistakes are so frequent that they’re an inside joke among programmers. The meme’s bottom panel basically shows the 0-index advocates performing mental acrobatics to avoid off-by-one errors: by sticking to strict rules (like always start counting at 0, or always loop with < length rather than <= length), they try to minimize those mistakes.

In summary, this comic is illustrating the clash between two ways of numbering things in programming:

  • One side says, "Let’s just count normally (1, 2, 3, ...)." This is simple and intuitive, but it doesn’t match the way many programming languages and computer hardware work.
  • The other side says, "Let’s count from 0 because that’s how computers naturally count." This is logical for the machine and helps avoid certain bugs, but it requires humans to adjust their normal counting habit.

Because different languages and systems chose different conventions, every programmer eventually encounters this indexing debate (and might even accidentally use the wrong convention in the wrong context!). The top part of the cartoon shows the 1-based camp being very straightforward (almost like a calm teacher insisting "the first item is number 1, of course"), and the bottom part shows the 0-based camp giving lots of detailed, technical reasons and looking a bit wild while doing so. It’s a funny exaggeration of discussions that actually happen among developers, especially when someone new asks why a language counts from 0. The bottom line: both methods work, but mixing them up will definitely cause confusion – just like calling the ground floor “1” vs “0” can make two people miss each other. It’s an inside joke that highlights how even something as simple as counting can become a passionate debate in computer science.

Level 3: Off-by-One Olympics

For seasoned developers, this comic is a comically accurate replay of an age-old conflict. If you’ve spent enough time programming, you’ve surely witnessed heated debates about one-based vs zero-based indexing – it’s right up there with spaces-vs-tabs in the pantheon of perpetual tech arguments. The meme nails the dynamic: the 1-index camp stands there calmly, offering a simple, almost self-evident rule – "just count like normal humans, 1, 2, 3, ... problem solved." The 0-index camp, on the other hand, is doing mental gymnastics worthy of an Olympic event (hence our "Off-by-One Olympics") to justify why starting at 0 is superior. And let’s be honest, many of us have performed those very gymnastics in real life when explaining code quirks to colleagues or during code reviews.

Why do the zero-based purists get so acrobatic in their explanations? Because they've been bitten by the consequences. Every experienced coder has a horror story of an off-by-one error. It's practically a rite of passage in software development. Maybe it was a loop that ran one iteration too many and caused an array out-of-bounds crash, or a fencepost mistake where you miscalculated an index and skipped processing the last item. These bugs are frustratingly common and can be catastrophic in low-level contexts – think buffer overflows or reading/writing past the end of an array. So the chaotic energy in the bottom panel reflects developers over-correcting for those mistakes: they've developed a dogmatic attachment to zero-based indexing because, in their experience, it reduces certain classes of errors and aligns with how their brain now thinks about memory.

Take, for example, a senior C programmer who's been on-call for production systems. They might insist, "Trust me, arrays must start at 0; anything else will mess up pointer math and modulo logic!". They've internalized patterns like using half-open ranges in loops (for (int i = 0; i < N; i++)) to neatly iterate N times without ever touching N itself. If someone proposes a one-based scheme, that old veteran vividly recalls the 3 AM incident where an index-out-of-bounds bug crashed a service – and they recoil as if someone suggested removing seatbelts from a car. The meme's bottom quotes are basically those justifications plucked from countless forum debates, for example:

  • Zero-based makes math easier for things like wrapping around with the % operator (common in circular buffer implementations or round-robin scheduling). This is a real convenience: imagine implementing a ring buffer where you do index = (index + 1) % N to move to the next slot. If index ranges 0 to N-1, it's clean. In a 1-based world, you'd constantly adjust that formula to avoid hitting an index 0 that doesn't exist, perhaps doing something like index = (index % N) + 1. It’s a small difference, but to a seasoned dev, avoiding that awkward adjustment feels cleaner and less error-prone.
  • The reminder that "a 5-element array has no index 5" is something every C/Java/Python tutor has had to patiently explain to newbies. It's an odd phrase out of context, but it's their way of saying: if you have 5 elements and you’re counting from zero, you label them 0 through 4. The moment someone tries array[5], you've gone off the edge. Seasoned devs repeat this fact like a safety mantra, hoping to ingrain it in newcomers and prevent those runtime exceptions or memory corruption scenarios.
  • The assembly argument ("assembly uses addresses and offsets, so high-level languages should too") appeals to the authority of the machine itself. It's a bit tongue-in-cheek – application developers don’t need to mimic assembly in most cases – but it’s a common refrain in systems programming circles. It’s akin to saying, "the CPU itself counts from 0, so any serious programming should respect that." More practically, it means if you ever drop down to low-level code, you'll think in terms of base addresses and offsets anyway. So the 0-index folks feel it's better to stay consistent with that model from the start, rather than juggle two mental models.

On the other side, the one-based advocates (often coming from mathematical or beginner-friendly environments) watch this circus of explanations with a kind of bemused serenity. To them, the first item is number 1, the second is number 2 – end of story. Why complicate something so simple? This perspective is common in environments like MATLAB, R, or spreadsheet formulas, where users are domain experts (scientists, analysts) who aren't thinking about memory addresses at all. When these folks step into a language like Python or Java that uses zero-based lists/arrays, they often get tripped up at first. I've seen a data analyst write a loop from 1 to N in Python and wonder why it missed the first element of the list – they assumed list indices started at 1 because that’s what they were used to. Cue the “inclusive-exclusive” confusion when they realize Python indices actually run 0 to N-1.

In team settings, these indexing differences can cause subtle bugs during integrations. Imagine a Python backend (0-indexed lists) communicating with a MATLAB algorithm (1-indexed arrays). If both sides aren't aware of the difference, you might end up off by one when exchanging data. For example, the MATLAB code might ask for the "3rd element" of a dataset, expecting index 3 in its 1-based mind, but the Python side might hand over what it thinks is the 3rd element (which would actually be index 2 in 0-based). These are real-life manifestations of off-by-one errors that come solely from misunderstanding each other’s indexing strategy. This is why seasoned engineers get a little pedantic about clearly documenting "this function expects 0-based indices" or "note: this API uses 1-based indexing". It's like making sure everyone is using the same map scale before plotting a route.

The "holy war" aspect comes from the fact that both sides find the other’s stance a bit vexing. The zero-based crowd sees one-based indexing as a recipe for naive mistakes and an anachronism in a world dominated by C-like languages. The one-based crowd sees zero-based indexing as an unnecessary complication – a prime example of programmers being obtuse and making things harder for non-programmers. Neither side is completely wrong, which is why the debate never truly dies. Instead, it’s become a light-hearted feud in programmer culture. Seasoned devs will crack jokes like "I have zero problems with zero-indexing," or tease a colleague with "Sure, start counting at 1… if you enjoy debugging off-by-one errors all night." It’s the kind of friendly ribbing you’ll see on forums or Twitter.

At the end of the day, the pragmatic senior view is: whatever the language’s indexing strategy is, just know it well and stick to it consistently. Be vigilant with your loop boundaries and array accesses. The meme resonates with experienced developers because it dramatizes this advice in a relatable way – representing the calm, straightforward approach versus the hyper-technical justifications. It humorously captures how something as trivial as “do we start counting at 0 or 1?” can lead to epic rants in the developer community. Indeed, like many classic tech debates, it never truly ends; it just goes into hibernation until the next time someone innocently asks, “Why don’t we index arrays from 1?” and the whole holy war flares up again.

Level 4: Half-Open Interval Gospel

At the deepest level, this meme touches on fundamental truths of computer science that border on numerical philosophy. The great array indexing debate has raged for decades: whether the first element should be designated as index 0 or index 1. In theoretical terms, this boils down to how we define the set of natural numbers and interpret sequences. Edsger W. Dijkstra famously argued that counting from zero is more elegant, aligning with the half-open interval convention [0, n). That is, an array of length n has valid indices from 0 up to n-1. This half-open range is considered a gospel of clarity among many computer scientists because it eliminates ambiguity about inclusive vs exclusive boundaries. If you want the first k elements, you take indices [0, k); if you want the last m elements of n, you consider [n-m, n). The number of elements in [i, j) is simply j - i — no +1 adjustments needed. Such cleanliness in formulae is a form of nirvana in algorithm design, removing the specter of those dreaded off-by-one errors through mathematically neat definitions.

From a low-level perspective, the zero-based indexing doctrine also arises from how memory works at the hardware level. In assembly and machine code, an array is essentially a contiguous block of memory, and the only way to locate an element is by computing an offset from the start address. If base is the memory address of the first element, the i-th element's address is calculated as base + i * (size of each element). If i = 0, this formula naturally gives the base address, meaning the first element lives exactly at the base. We can express it more formally:

$$ \text{MemoryAddress}(\text{arr}[i]) = \text{Address}(\text{arr}) + i \times \text{sizeof(element)},. $$

This equation beautifully encapsulates why arr[0] points to the base address itself: because it's offset by 0 * size. Now imagine if arrays were 1-indexed; the formula would shift to base + (i-1) * size, adding a cognitive (and computational) adjustment each time. Zero-based indexing thus aligns perfectly with pointer arithmetic: the index directly represents how many element-sized steps to move from the start. This alignment is not merely aesthetic — it was critical in languages like C (from K&R’s legacy) where array access is largely syntactic sugar for pointer math. In C, the expression arr[i] is defined as *(arr + i), meaning "start at the memory address arr and move i units forward". One-based indexing would complicate this definition, requiring subtle behind-the-scenes math to subtract 1 every time.

Historically, both strategies have their lineage. Early languages intended for mathematicians or educators often chose 1-based indexing as a natural way to mirror human counting: Fortran (1950s) defaulted arrays to start at 1 (though it allowed custom lower bounds), and mathematicians describing algorithms on paper often enumerate items as 1, 2, 3, ... up to n. Donald Knuth’s influential algorithms books often number array elements from 1 for clarity in English prose. However, the rise of system programming languages like C and later C++/Java/Python cemented zero-based indexing as the dominant orthodoxy. This is partly because of the aforementioned assembly consistency argument: at the machine level everything is zero-offset, so high-level languages followed suit to avoid confusion and optimize computations. It became a doctrine passed down through generations of programmers that "the first element is index 0", which nowadays feels as immutable as the laws of physics in most languages.

The humor in the meme’s contrast comes from the almost religious fervor behind each side's reasoning. The top panel's calm statement "Arrays should start at 1 because that is the 1st element" reflects a straightforward, almost naive truth: if we number things starting at one, the k-th item has label k, period. It’s an appealing simplicity rooted in everyday counting. Meanwhile, the bottom panel is a torrent of justifications for zero-based indexing that might sound like esoteric scripture to the uninitiated. Each stick figure’s speech bubble is basically reciting a verse from the Zero-Based Gospel:

  • “the second element is the first element. the first is the zeroth” – a zen-like paradox highlighting the linguistic confusion zero-indexing introduces (the idea that the "first" item is at position zero, so the "second element" lives at index 1). It's practically a mantra among C programmers that you get used to calling the first element index 0.
  • “zero-indexing is easier when you use a modulus operator to wrap indices” – this references a technical convenience: when cycling through array indices (like in a circular buffer or applying % to clamp indices within bounds), working with 0-based counting simplifies the math. For example, using index % N naturally yields a number from 0 to N-1, directly valid for 0-based indexing. If arrays were 1-based, wrapping around would involve an awkward shift (like using ((index - 1) % N) + 1 to get a 1-based result). The modulo arithmetic thus “fits” more gracefully with zero-based arrays, which is a niche but valid point in the gospel.
  • “an array with 5 elements doesn’t have a 5th element” – a slightly mischievous way to say in zero-index world, a collection of five items has indices 0,1,2,3,4. What a 1-index proponent would call the "5th element" is, in a 0-index system, at index 4. This statement is poking at the confusion beginners face: telling someone the array has 5 elements but “no 5th element” sounds absurd without context. Yet it's true: there is no element at index 5, because we'd count 0-4. It highlights the off-by-one confusion inherent in the differing systems.
  • “assembly language uses addresses and offsets so all languages should do the same for consistency” – this is the purist argument from a historical and performance perspective. Assembly (and by extension, CPU memory addressing) has no concept of a “first” vs “zeroth” element — it only knows that if you want the next item, you add the item’s size to the base address. High-level languages like C were designed as a thin abstraction over assembly, so they adopted 0-based indexing to stay consistent with low-level mechanics. The stick figure here is basically saying "the machine already counts from 0, so should we." It’s an appeal to a kind of first principles argument: deviating from the hardware’s way is heresy to these folks.
  • “arr(0) is the memory region from &arr + 0dtypeSize to &arr + 0dtypeSize + dtypeSize” – this one dives into a mnemonic about memory layout. &arr denotes the address of the array in memory (the start of the block). If dtypeSize is the size of each element, then arr(0) occupies memory from address &arr + 0*dtypeSize up to &arr + 0*dtypeSize + dtypeSize. In short, the first element begins exactly at the start address and spans one element’s size. The phrasing is a bit jumbled in the meme text, but they’re effectively describing how the memory offset for index 0 is zero bytes. It's a pedantic way to reinforce that index 0 corresponds to "no offset from the start," which is a core reason many find it natural in low-level programming to count this way.

In contrast, the serene top panel doesn’t need all these acrobatics. It just states one simple axiom and stands on it firmly: "the first element is 1 because that's how humans count things by default." The meme exaggerates the gymnastics the zero-based purists perform (literally drawn as acrobats on uneven bars and ropes) to justify what might seem convoluted to a layperson. Yet, as convoluted as these arguments sound, they reflect real design trade-offs and historical reasons. The outcome is an eternal holy war in programming culture — much like debates over tabs vs spaces or vim vs emacs — where each side has internally consistent reasoning. And as the meme title alludes, "Holywar... holywar never changes", the joke is that for all our progress in computing, some debates are timeless. Zero vs one indexing is one of those immortal battles, with seasoned programmers bearing scars (or at least strong opinions) from countless flamewars on the topic.

Comments (99)

  1. Anonymous

    1-based indexing is like telling a story starting with 'Chapter 1.' 0-based indexing is like starting with the prologue, because you know the real context begins before the main plot

  2. Anonymous

    Some architects still push for 1-based arrays - because nothing says "high availability" like an off-by-one that ships straight into prod capacity charts

  3. Anonymous

    The only thing more permanent than our temporary workarounds is the array indexing debate that derails every language design meeting since 1957

  4. Anonymous

    After 20 years in the industry, I've realized zero-indexed arrays are like UTC timestamps - technically correct, mathematically elegant, and the source of 90% of off-by-one bugs in production. The real genius move? Languages like Lua starting at 1, forcing you to do mental gymnastics in *reverse* when interfacing with literally every other system. At least with zero-indexing, the cognitive dissonance is consistent across your entire stack... until you hit SQL's SUBSTRING(str, 1, n) and remember that even within zero-indexed languages, some stdlib functions said 'nah, we're good.'

  5. Anonymous

    Zero-based indexing: base + i*sizeof(T) compiles to a single LEA; one-based turns every access into an off-by-one postmortem

  6. Anonymous

    Ask for 1-based arrays and you’re volunteering to rewrite every ring buffer, bitmap, and SIMD stride - zero-based is less ideology and more the reason the postmortem fits on one page

  7. Anonymous

    Zero-based wins: assembly pointers hit the first element at offset 0 - no modulo tax, just pure cache-line bliss

  8. @Araalith

    The index is just an offset. But, IMO, arrays should start from whatever index a developer wants.

  9. @dev_key

    question mark

  10. @peajack

    indices should start at 1, offsets should start at 0

  11. @Algoinde

    Arrays should end at 0

  12. @MakarovAstronom

    Arrays should start from zero, so that when cpu need to calculate address of a member by index, it does not have to subtract 1 every time

  13. @azizhakberdiev

    binary tree in 0 indexed array: (i*2+1) (i*2+2) binary tree in 1 indexed array: (i*2) (i*2+1)

  14. @azizhakberdiev

    bonus: null pointer is a potentially valid address in memory area

  15. Yuri

    When somebody asks you: "how many dicks did you sucked?" The pool of possible answers should start with Zero. If that logic does not apply to you, it's ok, Imma allow you to start your arrays with 1.

  16. @deadgnom32

    if you don't like arrays that start at 0 — just ignore the 0th element. 😎

  17. @niklashh

    Natural numbers start at zero and array lenghts are natural numbers. It's so obvious

  18. @SamsonovAnton

    Just as it is incorrect to refer to 0x10 as "ten", it may be a bad idea to use 1-based ordinal numeral to refer to 0-based indexes. The only exception to this rule would be storing polynomial coefficients. But then your indexing system must support negative indices, which is not usually the case, unless a language like Basic (originally 1-based) is used.

  19. @paletteOvO

    just skip the 0 and place data from 1 :p

  20. @ashit_axar

    Some languages use index-0 as the array length. That makes calculations much easier and obviously you don't have to walk the array to find the length. But i think C has one great benefit that

Join the discussion →

Related deep dives