In modern languages, you may think of it as tradition. There is a reason why it was done so originally though, and that reason was: to conserve memory.
(EDIT: Since 2 people have completely snapped already; I understand that arrays could have been implemented differently in C. The fact remains that they weren't. They really are just pointers in C, and C just so happens to be the ancestor of most modern languages which start at 0. - There may be other reasons to start at 0, I am merely providing the one related to how arrays work in the ancestor of C-style languages... the programming language C. Not Fortran, but C. Thank you for your understanding.)
The godfather of general-purpose programming languages, C (and by extension, C++), considers certain variables as memory addresses called pointers. These days, memory management is left up to the runtime environment, not the programmer which is why you've probably never heard of pointers. But when you use C, when you use variables, you're really dealing with the memory in a less abstract fashion.
This may be way too complicated if you're new to programming, but hopefully this will make some sense.
A pointer is a kind of variable that stores a memory address. In C, you can work with "normal" variables but they are limited in a number of ways... you always end up having to work with so-called pointers, which you may consider a different kind of variable, one that points to a location in memory, rather than the actual content of that location in memory. I will skip the discussion on why this is, just remember that pointers are variables containing memory addresses which then are used to point toward the data... as opposed to storing the data itself. ("Normal" variables are said to be located on the stack, but pointers are said to be located on the heap - nevermind this if it confuses you.)
In C, when you use an array, what you really have is a memory address (a pointer) indicating the start of the array. The pointer itself doesn't contain the content, it doesn't even contain the length of the array, merely the memory address of its starting point. But when you allocate that memory, you have to specify exactly how large the array is, so that the compiler will know how much memory to allocate.
Let's imagine an array in C called some_array.
some_array will determine the memory location of the array. The array itself is nothing but a sequence of reserved memory address space where the content of some_array is expected to reside. When we create that array, we give it a name (some_array), and we tell it how many items in the array we need. (In C/C++, arrays don't expand on demand, you have to declare their size beforehand or otherwise use more complicated classes like lists or vectors).
But now we want the second entry in our array. How do we figure out where it is? We only have the memory address, the pointer! That doesn't tell us where the second entry is, merely where the first entry starts!
But what we do know (in C), is the size of the variable type of our array... which also must be explicitly stated when you create the array. If we have an integer, for instance, let's say it's 16 bits in size.
We can then know the location of the second entry by knowing the location of the first entry (which is the start of the array), and then we can simply add the size of each entry (size of integer)!
In other words;
location_of_second_entry = location_of_first_entry + (size_of_integer).
What about the third entry? That will be:
location_of_third_entry = location_of_first_entry + (2 * size_of_integer).
As you might be able to tell, the physical memory location will always be as follows:
location_of_any_entry = location_of_first_entry + (iterator * size_of_integer)
So if you want the first item, the iterator will be 0. And that's why iterators originally started as 0, because the variables used to denote arrays were typically just memory addresses.
Now, this wouldn't have to work this way. You might start at 1 in C, but then you would be wasting the address space between the first entry and the second one because "location_of_first_entry" would never be used to store any data.
Memory management is handled completely differently in more recent runtimes and languages, so this is not really a technical requirement for more high-level programming languages (such as PHP, Python, Perl), but it's a tradition that has lived on because there was a time when programmers were expected to handle memory with some respect.
In more high-level languages, the question of whether to start from 0 or 1 is mostly a question of how much programmers feel like arguing about it. So, in the end of the day for 2011 and super-high-level programming languages, it's really just a tradition. - Apparently I'm a complete idiot that knows nothing about anything, spouting utter nonsense to the detriment of humanity and the world as we know it. Well, actually, I just neglected to take into account the modern debate and so I have earned the wrath of those who graciously know better. Turns out there's a perfectly rational debate around this that relates to modern languages, independent of the historical reasons behind C-style languages. So while the historical reason for C-style languages taking it from C is true, there is apparently a deeper discussion as well, as it turns out.
(EDIT: Since someone mentioned it, this was done differently, starting at 1, in other low-level programming languages like Fortran. The reason it was done this way in C is because of how arrays are implemented in C. They could have implemented them differently, in which case it could have started at 1 without wasting memory, but they didn't.)