Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

A question asked here reminded me of a discussion I had with a fellow programmer. He argued that zero-based arrays should be replaced with one-based arrays since arrays being zero-based is an implementation detail that originates from the way arrays and pointers and computer hardware work, but these sort of stuff should not be reflected in higher level languages.

Now I am not really good at debating so I couldn't really offer any good reasons to stick with zero-based arrays other than they sort of feel like more appropriate. Why is zero the common starting point for arrays?

share

migrated from stackoverflow.com Sep 26 '11 at 18:19

This question came from our site for professional and enthusiast programmers.

locked by Yannis Rizos Mar 13 '12 at 20:42

This question exists because it has historical significance, but it is not considered a good, on-topic question for this site, so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. More info: help center.

39 Answers 39

up vote 105 down vote accepted

I don't think any of us can provide a stronger argument than Edsger W. Dijkstra's article "Why numbering should start at zero".

share
6  
Dijkstra's article is about style, but then, his arguments are about simplicity and ease of use... +1. –  paercebal Dec 31 '08 at 17:17

Code including some original position/relative position information are much cleaner with arrays starting at 0.

For instance : The code to copy a vector at a defined position in a bigger vector is a pain with arrays starting at 1 :

function copyAtPos (dest, vect, i):
    for i from 1 -> vect.length do
        dest[pos+i-1] = vect[i]

By opposition with arrays starting at 0:

function copyAtPos (dest, vect, i):
    for i from 0 -> vect.length-1 do
        dest[pos+i] = vect[i]

If you begin writing big convolutions formula, it becomes a must.

share

You can, but compiler optimizations are free to create invalid results (gcc and msvc won't, but clang will).

char* myArray = malloc(100) - 1;
/* now myArray[1] is the first element, and myArray[100] is the last. */
free(myArray + 1);

But, as other people have mentioned, don't do this. Un-learn your bad habits of starting at 1.

Another solution: Just ignore the first element of the array.

share

because array names are constant pointers to array starting positions. For example In C array[2] is turned into array + (sizeof(array)*2), which will give you two elements beyond the starting element(third element:)). so if you want to reach the starting element, with the same math, you should do

array + (sizeof(array)*i) = array

(sizeof(array)*i) = 0

i = 0

simple equation math.

share

It's certainly possible but the C language does not support this. Many other languages such as Fortran, PL/1, Pascal, Modula2, Ada support this.

It was part of the C language design to keep the compiler simple and small and it would break too many things to change it now.

share

C is a very simple language (or so they say). Its design was based strongly on available hardware features, i.e. on ease of implementing the compiler. Indexing an array translates directly into pointer arithmetic, so:

int array[256];
int i = 10;
...
array[i] = 12;

translates into something like:

*(array + i*sizeof(int)) = 12;

or in imaginary intermediate machine language:

load value of array into register Ra
load value of i into register Rb
right shift Rb by X number of bits
add value in Rb to value in Ra
store value 12 at address in Ra

(Note: here array is the address fixed at load time, so I say "load value of array" - it's a bit different for indexing a pointer, one more indirection is required to obtain the base address.)

With this in mind zero-based indexing is only natural.

share

If you insist on having your arrays start at 1...

type real_foo[COUNT], *const foo=real_foo-1;

If you're really sadistic, you could even make a preprocessor macro to do this for you...

#define CONCAT(x,y) x ## y
#define ARRAY1(name,size) CONCAT(real_, name), *const name=CONCAT(real_, name)-1
type ARRAY1(foo, COUNT);

Hope I didn't screw up those macros...

share
1  
Technically it's UB to take a "one off the beginning" pointer in C, unlike the "one off the end" pointer which is valid. In practice you'll get away with it now that we all use machines with flat address spaces. The code you have might provoke a compiler warning sometimes, though. –  Steve Jessop Jul 25 '10 at 16:34

An array in C is shorthand for pointer arithmetic. Consider this case:

struct Foo *foo;
struct Foo foos[10];

foo = &(foos[1]);
foo = foos + (1 * sizeof(struct Foo));

The last two lines mean the same thing. Changing the initial offset would break this correlation, making many things in C much more difficult.

Some languages with a very strict Array type, like Pascal, allow you to start counting in other ways. But in C, and in many languages derived from C, arrays are just shorthand for pointer arithmetic, so you can't mess with their starting index.

share

It's because of how arrays are constructed. It doesn't make a lot of sense for them to start from one. An array is a base address in memory, a size, and an index. To access the nth element, it's:

base + n * element_size

So 0 is obviously the first offset.

share

It is possible if you take care while writing your "own" code. You can assume your index starts from n for all n>=0 and program accordingly.

Regarding standard, Borealid has a great argument.

share

The reason it starts at 0 and not 1 is that the you can think of the offset as how far from the beginning of the array's memory is this element. It's not saying give me the 0th element -- it's saying, give me the element who is 0 elements from the start.

Another way to look at it is that these are (for the most part) equivalent:

array[n]

*(array + n)

The reason the standard won't ever be changed is because C has been around for about 40 years now. There is no compelling reason to change it and if they did, all of the existing code that depends on the start of the array being at 0 would be broken.

share

Why do you want arrays to start at one?

When you say a[x][y], the compiler translates this into: a+(x*num_cols+y). If arrays started at one, this would become a+(x*num_cols+y-1). This would be an extra arithmetic operation every single time you want to access an array element. Why would you want to slow down programs?

share
1  
actually, it would have to become a + ((x - 1) * num_cols) + y - 1) -- both x and y would start from 1. –  Dennis Munsie Jul 25 '10 at 19:25

Because there is a strong correlation between arrays and pointers in C

char* p = "hello";
char q[] = "hello";

assert(p[1] == q[1]);

assert(*p == *q)

*p is the same as *(p + 0)

having a starting index of 1 will give you headache later

share

Using 1-based arrays, transform a single-dimension array into a multi-dimensional array:

int w = 5, h = 5, d = 5;

int[] a1 = new int[w * h * d], new a2 = int[w,h,d];

for (int z = 1; z <= d; z++)

  for (int y = 1; y <= h; y++)

    for (int x = 1; x <= w; x++)

      a1[x + (y - 1) * w + (z - 1) * h] = a2[x,y,z];

Note that your y and z indexes are 0-based (y - 1, z - 1) even when your array is 1-based. Under some circumstances, you can't avoid 0-based indexes. For consistency, why not always use 0-based indexes?

share

I'm betting the programmer was just annoyed with the counter-intuitiveness of a 0 based array in day to day thinking and was arguing for a more intuitive means of describing arrays. I find it ironic that as humans we spent so much time to come up with "classes" so that we could describe things in a more human way in our code, but then when looking at 0 vs 1 arrays we seem to get hung up on the logic of it alone.

As far as the computer is concerned and mathematically 0 is going to probably be better, but I feel a point is being missed here. If we wanted to describe things in a more human way (e.g. classes), why wouldn't we want the same for other parts of the language? Is that not equally logical or valid (or take higher priority for that matter...) to make a language more easily understandable and usable to humans and thus, by extension, less prone to scenarios that tend to create logic-bugs and more prone to faster production of a usable creation. PHP Example:

array(1 => 'January', 'February', 'March');

gives a 1 based array per our request.

Why not have the norm:

array('January', 'February', 'March');

And the exception be:

array(0 => 'Value for scenario where 0 *has* to be used as the key',
      'value2', 'value3');

In the case of say PHP, my bet is 80% of the time a 1 based array being the default syntax-wise would decrease logic-bugs in real world use cases, or at least not cause more on average, while making it a lot easier on the coder to produce usable code quicker. Remember, I'm assuming there would still be the option of, array(0 => 'value') for when it's needed, but also assuming the majority of the time it's practical to have something closer to a real world description.

This really doesn't sound too far fetched of a request when looking at it from that perspective. When approaching an interface, be it an OS or a language for a programmer, the closer to human thinking and habits we design it around, the happier in most cases we will be and the less misunderstandings between the human and the computer(human logic-bugs), and the faster production, etc. we will have. If 80% of the time in the real world I describe things with 1 when making lists or counting, then the computer should ideally interpret my meaning into a way it understands with as little information or change from my normal way of describing something as possible. In short the closer we can model the real world, the better quality the abstraction. So what he wants is by no means stupid since that is the ultimate goal and would be evidence of a need for more abstraction. The computer can still ultimately see it as a special use of a 0 based array. I could care less how the computer interprets it so long as it's a simpler and more intuitive way for me to describe what I want to it with less bugs over time.

So, that's my two cents. I seriously doubt what he was saying, or what was interpreted, was what he meant. What he probably meant was, "I hate having a less-intuitive way of telling the computer what I want." :) Don't we all? lol.

share

I prefer 0-based arrays because, as mentioned by others, it makes math easier. For example, if we have a 1-dimensional array of 100 elements emulating a 10x10 grid, then what is the array index i of the element in row r, col c:

0-based: i = 10 * r + c
1-based: i = 10 * (r - 1) + c

And, given the index i, going back to the row and column is:

0-based: c = i % 10
         r = floor(i / 10)
1-based: c = (i - 1) % 10 + 1
         r = ceil(i / 10)

Given that the math above is clearly more complex when using 1-based arrays, it seems logical to choose 0-based arrays as the standard.

However, I think that someone could claim that my logic is flawed because I assume that there would be a reason to represent 2D data in a 1D array. I have run into a number of such situations in C/C++, but I must admit that needing to perform such computations is somewhat language dependent. If arrays truly performed all index math for the client, all the time, then the compiler could simply convert your M-based array accesses to 0-based at compile-time and hide all of these implementation details from the user. In fact, any compile-time constant could be used to do the same set of operations, although such constructs would probably just lead to incomprehensible code.

Perhaps a better argument would be that minimizing the number of array index operations in a language with 1-based arrays would require that integer division be performed using the ceiling function. However, from a mathematical perspective, integer division should return d remainder r, where d and r are both positive. Therefore, 0-based arrays should be used to simplify math.

For example, if you are generating a lookup table with N elements, the nearest index prior to the current value into the array for value x would be (approximately, ignoring values where the result is an integer prior to rounding):

0-based with floor: floor((N - 1) * x / xRange)
1-based with floor: floor((N - 1) * x / xRange) + 1
1-based with ceil : ceil ((N - 1) * x / xRange)

Notice that if the standard convention of rounding down is used, 1-based arrays require an additional operation, which is undesirable. This kind of math cannot be hidden by the compiler, as it requires lower-level knowledge about what is happening behind the scenes.

share

As a 10+yr C/C++ programmer, with a very strong background in Pascal and Delphi, I still miss Pascal's strong array bound and index type checking, and the flexibility and safety that comes with it. An obvious example of this is an array data holding values for each month.

Pascal:

 Type Month = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);

  Var Days[Month] of integer;

  ... 
  if Year mod 4 = 0 then // yes this is vastly simplified for leap years and yes i don't know what the comment marker is in pascal and no i won't go look it up
    Days[Feb] := 29
  else
    Days[Feb] := 28;

Writing similar code in C languages without using +/-1's or 'magic numbers' is pretty challenging. Note that expressions like Days[2] and Days[Jan+Dec] simply won't compile, which can appear brutal to people who still think in C or Assembler.

I have to say there are many aspects of Pascal/Delphi languages that I don't miss a bit, but C zero-based arrays do seem just "dumb" by comparison.

share
2  
I know ;-) However, it was correct for the year 2000. I'm just playing "spot the pedant"... –  Roddy Dec 27 '08 at 8:51

With zero-based arrays, you can use an unsigned int as the index and then you don't have to test for index out of range on the lower bound. e.g:

int GetValue(unsigned index)
{
    ASSERT(index < arraySize);
    return(array[index];
}
share

Have you ever been annoyed by "20th century" actually referring to the 1900s? Well, it's a good analogy for the tedious things you deal with all the time when using 1-based arrays.

Consider a common array task like the .net IO.stream read method:

int Read(byte[] buffer, int offset, int length)

Here is what I suggest you do to convince yourself 0-based arrays are better:

In each indexing style, write a BufferedStream class that supports reading. You may change the definition of the Read function (eg. use a lower bound instead of an offset) for the 1-based arrays. No need for anything fancy, just make it simple.

Now, which one of those implementations is simpler? Which one has +1 and -1 offsets sprinkled here and there? That's what I thought. In fact I would argue that the only cases where the indexing style doesn't matter is when you should have used something that wasn't an array, like a Set.

share

The only two (very) serious reasons to used 0-based indices instead of 1-based indices seem to avoid reeducating a lot of programers AND for backward compatiblity.

I didn't see any other serious arguments against 1-based indices in all the answers you received.

In fact, indices are naturally 1-based, and here is why.

First, we must ask : Were does arrays come from ? Do they have real-world equivalents ? The answer is yes : they are how we modelize vectors and matrix in computer science. However, Vectors and matrix are mathematicals concepts that were using 1-based indices before the computer-era (and that still mostly use 1-based indices nowaday).

In the real world, indices are 1-bases.

As Thomas said above, languages that used 0-bases indices are in fact using offsets, not indices. And developers who are using these languages think about offsets, not indices. This would not be a problem if things were clearly stated, but they are not. A lot of developers using offsets still talk about indices. And a lot of developers using indices still don't know that C, C++, C#, ... use offsets.

This is a wording problem.

(Note about Diskstra's paper - It says exactly what I have said above : mathematician do use 1-based indices. But Diskstra think that matematicians should not use them because some expression would then be ugly (eg.: 1 <= n <= 0). Well, not sure he is right on that one - doing such a paradigm shift in order to avoid those exceptional empty sequences seems a lot of trouble for a little result...)

share
2  
Mathematicians don't always use 1-based indices. I've seen x0 used plenty of times for the initial value of a sequence. It depends on whichever is more convenient. –  Adam Crume Jun 17 '10 at 20:13

It is just so, and has been for many years. To change it, or even to debate it, is just as pointless as to change or debate changing traffic lights. Let's make blue=stop, red=go.

Look into changes made over time in Numerical Recipes for C++. They had used macros to fake 1-based indexing, but in the 2001 edition gave up and joined the herd. There may be enlighting material on the reasons behind this at their site www.nr.com

BTW, also annoying is the variants of specifying a range out of an array. Example: python vs. IDL; a[100:200] vs a[100:199] to get 100 elements. Just gotta learn the quirks of each language. To change a language that does it one way to match the other would cause such cussing and gnashing of teeth, and not solve any real problem.

share

It is hard to defend 0-base without programming a lot of array-based code, such as string searching and various sorting/merging algorithms, or simulating multi-dimensional arrays in a single-dimension array. Fortran is 1-based, and you need a lot of coffee to get this kind of code done right.

But it goes way beyond that. It is a very useful mental habit to be able to think about the length of something rather than the indices of its elements. For example, in doing pixel-based graphics, it is much clearer to think of coordinates as falling between pixels rather than on them. That way, a 3x3 rectangle contains 9 pixels, not 16.

A little more far-fetched example is the idea of look-ahead in parsing, or in printing sub-totals in a table. The "common-sense" approach says 1) get the next character, token, or table row, and 2) decide what to do with it. The look-ahead approach says 1) assume you can see it, and decide if you want it, and 2) if you do want it, "accept" it (which allows you to see the next one). Then if you write out the pseudo-code, it is much simpler.

Still another example is how to use "goto" in languages where you have no choice, such as MS-DOS batch files. The "common-sense" approach is to attach labels to blocks of code to be done, and label them as such. Often a better approach is to put labels at the ends of blocks of code, for the purpose of skipping over them. This makes it "structured" and much easier to modify.

share

The index in an array is not really an index. It is simply an offset that is the distance from the start of the array. The first element is at the start of the array so there is no distance. Therefore the offset is 0.

share
3  
For most languages that get designed nowadays, this is really an implementation detail, which shouldn't appear in the language (except when there are other better reasons to do so) –  Jens Schauder Sep 6 '09 at 19:42

I prefer 0 based index since since modulo (and the AND operator when used for modulo) always returns 0 for some values.

I often find myself using arrays like this:

int blah = array[i & 0xff];

I often get that kind of code wrong when using 1 based indices.

share

Personally, the one argument is when seeing array indexes as offsets. It just makes sense.

One could say that its the first element, but the offset of the first element relative to the origin of the array is zero. As such, taking the array origin and adding zero will yield the first element.

So in computing its easier to add zero to find the first element than to add one and then remove one.

I think anyone who did some lower level stuff always think the base zero way. And the people who are beginning or used to higher level often not-algorithmic programming might wish for a base one system. Or maybe we are just biased by past experiences.

share

Authority argument

Well... Apparently, most languages, including very recent ones, are zero-based. As those languages were written by quite skilled people, your friend must be wrong...

Why one?

why 1 would be a better starting index than zero? Why not 2, or 10? The answer itself is interesting because it shows a lot about the though process of the people defending the idea.

The first argument is that it's more natural, because the 1st is usually the one before all others, at least, for the majority of people...

The number-one argument is that the last index is also the size of the array...

I'm still impressed by the "quality" of the reasons I usually hear for this kind of arguments... And even more when I'm reminded that...

Why not zero?

... "One-based" notations are left-overs from the western culture that ignored the existence of zero for centuries, if not more.

Believe it or not, the original gregorian calendar goes from -3, -2, -1, 1, 2, 3... Try to imagine the problem it contributed to western science (for example, how many years from 1st January -2 to 1st January 2 to see than the original gregorian calendar conflicts with something as simple as substraction...).

Keeping to one-based arrays is like (well, I'll be downmodded for that... ^_^ ...), keeping to miles and yards in the 21th century...

Why Zero? Because it's math!

First (OOops... Sorry... I'll try again)

Zero, Zero is nothing, one is something. And some religious texts hold that "At the beginning, there was nothing". Some computer-related discussion can be as burning as religious debates, so this point is not so out of topics as it seems... ^_^

First, It's easier to work with a zero-based array and ignore its zero-th value than work with one-based array and hack around to find its zero-th value. This reason as almost as stupid as the previous, but then, the original argument in favor of one-based arrays was quite a fallacy, too.

Second, Let's remember that when dealing with numbers, chances are high you'll deal with math one moment or another, and when you deal with math, chances are good you are not in the mood for stupid hacks to get around obsolete conventions. The One-based notation plagued maths and dates for centuries, too, and by learning from our mistakes, we should strive to avoid it in future oriented sciences (including computer languages).

Third, As for computer language arrays being tied to hardware, allocate a C array of 21 integers, and move the pointer 10 indices to the right, and you'll have a natural [-10 to 10] array. This is not natural for hardware. But it is for maths. Of course, math could be obsolete, but the last time I checked, most people in the world believed it was not.

Four, As already pointed elsewhere, even for discrete position (or distances reduced to discrete values), the first index would be zero, like the floor in a building (starting at zero), the decreasing countdown (3, 2, 1, ZERO!), the ground altitude, the first pixel of an image, the temperature (zero Kelvin, for the absolute zero, or zero centigrade degrees, as water freezing temperature of 273 K). In fact, the only thing that really starts with one is the traditional way of "first, second, third, etc." iteration notation, which leads me naturally to the next point...

Five the next point (which naturally follows the previous) is that high-level containers should be accessed, not by index, but by iterators, unless the indices themselves have an intrinsic value. I'm surprised your "higher-level-language" advocate did not mention that. In the case the index itself is important, you can bet half the time you have a math-related question in mind. And thus, you'd like your container to be math-friendly, and not math-disabled like "thy olde gregorian calendar" starting at 1, and needing regurgitated hacks to make it work.

Conclusion

The argument given by your fellow programmer is a fallacy because it needlessly ties spoken/written language habits, which are, by nature, blurry, to computer languages (where you don't want your instruction blurred), and because by attributing wrongly an hardware reason to this problem, he.she hopes to convince you, as languages go higher and higher in abstraction, that the zero-based array is a thing of the past.

Zero-based arrays are zero-based because of math-related reasons. Not for hardware-related reasons.

Now, if this is a problem to your fellow programmer, have him start to program with real high level constructs, like iterators and foreach loops.

share
2  
I know (I have a Master diploma on Physics), but I felt playing with decimals was less the point than the humorous side I tried to color my arguments with... ^_^ ... –  paercebal Dec 31 '08 at 17:08
20  
Your paragraphs are labelled "Zero, First, Second, Third, Four, Five". For consistency, you ought to either use cardinal numbers ("Zero, One, Two, Three, Four, Five") or ordinal numbers ("Zeroth, First, Second, Third, Fourth, Fifth"). :-) –  ShreevatsaR Feb 16 '10 at 21:35
10  
Similarly, for the first year of our lives, we are not one year old but zero years old –  ChrisV Jun 11 '10 at 11:42
3  
@Nikita Rybak: What is amazing is that you missed what was seen by all commentators before you: Of course Bill the Lizard's answer is the right one. This is why I voted him a +1, and this is why it was chosen as the question's best answer. My answer is more about making fun of the fallacious reasons behind 1-based arrays, and offering concrete cases where a 1-based array would be a nuisance. Still, I'm surprised you found "not a single convincing one", even considering the reasons are mixed with irony... –  paercebal Oct 20 '10 at 15:13

Zero is natural when talking about the location of an item in a linear collection.

Think of a shelf full of books - the first book is located flush with the side wall of the shelf - that's location zero.

So I guess it depends on whether you consider array indices a means of finding things or referring to things.

share

I'm going to step out on a limb here and suggest something different than an integer 'keyed' array.

I think your coworker is getting at creating a one to one mapping of a 'set' in the physical world where we always start counting at 1. I can understand this, when you are not doing anything fancy, it is easy to understand some code when you are mapped 1 to 1 between software and the physical world.

My suggestion

Don't use integer based arrays for whatever you are storing, but use some other kind of dictionary or key value pair. These map better to real life as you aren't bound by an arbitrary integer. This has its place and I would recommend using it as much as you can due to the benifits of mapping concepts 1 to 1 between software and the physical world.

i.e. kvp['Name Server'] = "ns1.example.com"; (This is just one out of a million possible examples).

Discaimer

This most definitely not work when you are working with concepts based in mathmatics, basically because math is closer to the actual implementation of a computer. Using kvp sets are not going to help anything here, but will actually mess things up and make it more problematic. I haven't thought through all the corner cases where something may work better as kvp or as an array.

The end idea is to use the zero-based arrays or key value pairs where it makes sense, remember that when you only have a hammer, every problem starts looking like a nail...

share

My feeling is that it's completely arbitrary. There's nothing special about zero- or one-based arrays. Since liberating myself from Visual Basic (mostly, sometimes I do tiny things in Excel) I haven't worked with 1-based arrays, and... it's the same. The fact is that if you need the third element of the array, it's just an implementation detail that it is called 3 or 2. However, 99% of the work you do with arrays is only interested in two absolute points: the first element and the count or length. Again, it's just an implementation detail that the first element is called zero instead of one, or that the last element is called count-1 or, instead, count.

Edit: Some of the answerers have mentioned that 1-based arrays are more prone to fencepost errors. In my experience, thinking about it now, this is true. I remember thinking, in VB, "this will either work or will blow up because I'm off by one." In Java that never happens. Though I thought I was getting better, some of the answerers point out cases in which 0-based arrays result in nicer arithmetic, EVEN when you don't have to deal with a lower-level lang.

share

A heap is one example of the advantages to 1-based arrays. Given an index i, the index of i's parent and left child are

PARENT[i] = i ÷ 2

LCHILD[i] = i × 2

But only for 1-based arrays. For 0-based arrays you have

PARENT[i] = (i + 1) ÷ 2 - 1

LCHILD[i] = (i + 1) × 2 - 1

And then you have the property that i is also the size of the sub-array to that index (i.e. indices in the range [1,i]).

But in the end it doesn't matter, because you can make a 0-based array into a 1-based array by allocating one more element than normal, and ignoring the zeroth. Thus you can opt-in to get the benefits of 1-based arrays when appropriate, and keep the 0-based arrays for cleaner arithmetic in almost all the other situations.

share

Not the answer you're looking for? Browse other questions tagged or ask your own question.