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.

show 4 more comments

39 Answers

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
add comment

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
add comment

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.

share
add comment

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.

share
3  
0 is just as much the first binary number as it is the first decimal number. Not compelling. –  Jay Bazuzi Dec 26 '08 at 5:06
add comment

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
add comment

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
show 1 more comment

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
add comment

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
add comment

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
add comment

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