112
votes

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?

3
  • In an n-element array, the element 'n' is not present . A n-element array has members which number from 0 to n-1 only. So, isn't it better if we have an array starting from 1 and so an n-element array actually represents the n elements present in the array.
    – Karthik Balaguru
    Commented Jul 25, 2010 at 15:14
  • I like zero-based arrays because of the first bit in a byte is 2^0, not 2^1. This helps me sometimes :)
    – e-MEE
    Commented Sep 26, 2011 at 18:46
  • If one looks at this list for example, en.wikipedia.org/wiki/…, one will notice that most domain specific languages start indexing at 1, and most languages from cs school of thinking at 0. If one searches for a bit longer, he will notice that so many stupid discussions have been made on this subject, that it is probably pointless to try to talk any of the two to change their ways. In defend of "1", most people in the world use that one. Most programmers use "0". Most people don't understand programmers, so that makes you think ...
    – Rook
    Commented Sep 26, 2011 at 20:21

39 Answers 39

1
2
1
vote

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.

1
vote

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.

0
votes

I think that when you're trying to think about how your code works at a lower level, if this becomes necessary, zero-based arrays map more nicely to this lower level. Also, I'd assume that you'd need an extra add instruction for every dereference of a one-based array to make the pointers work correctly. I see one way around this (make the pointer point to the -1st/0th element of the array, not the 0th/1st), but that might wreak havok with garbage collectors, since you now have pointers pointing outside their allocated blocks.

0
votes

At the most atomic level, its simply due down to being binary.

0   =>  0 
1   =>  1
10  =>  2
11  =>  3

"0" is the first binary number, and likewise arrays are index by their "first" binary number.

Also, given An arbitrary base address for a dataset, the first record exists at that address, not that address + 1,

$base = 010110; 
$firstvalue  = $base + 0 * $unitsize
$secondvalue = $base + 1 * $unitsize
$thirdvalue  = $base + 2 * $unitsize

If you had a "1" based array the internal system would have to constantly decrement the target value by 1 to find the underlying memory address that data was stored at.

0 is just as much the first binary number as it is the first decimal number. Not compelling.

Write the number "0" on a page. How many numbers do you have?

If I have the numbers 500 to 550 on the page, how many numbers do I have? I have 51! But the difference is only 50.

Put 50 sheep in a paddock. Surprisingly, none of them look like numbers, but they are still a countable volume.

We however have this crazy idea that when a sheep looks a little bit too much like a 0, it must not be used, and it must be thrown out and we have to find a sheep looking like 50 to take its place.

Simplified

Use 1 to N for counting. But 0 is still a valid place holding symbol, and as such, it should be used.

If 0 is not a valid place holding symbol, then we should scrap 10, 20, 30, 40 ... etc from our number system, and go straight from 9 to 11.

1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 21 22 23 24 25 26 27

In essence, we humans not starting with "0" is a CULTURAL thing. Its not a rational one.

1
  • 3
    0 is just as much the first binary number as it is the first decimal number. Not compelling.
    – Jay Bazuzi
    Commented Dec 26, 2008 at 5:06
0
votes

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];
}
0
votes

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...

2
  • 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. Commented Jul 25, 2010 at 16:34
  • Indeed, I should have mentioned that. Commented Jul 25, 2010 at 17:20
0
votes

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.

0
votes

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.

0
votes

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.

1
2

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