views:

336

answers:

8
#include<stdio.h>
int main()
{
  char a[5]="hello";
  puts(a);  //prints hello
}

Why does the code compile correctly? We need six places to store "hello", correct?

+6  A: 

The C compiler will let you run off the end of arrays, it does no checks of that sort.

greg
Arrays don't have bounds checking in applications, either.
Brian
but such checks do happen in C++, right?
Lazer
As a general statement, this is incorrect, because the C Standard does permit compilers to insert checks as they see fit (what happens is _undefined_ behavior, but that doesn't mean that a particular compiler cannot define it); and, indeed, some compilers do insert array bound checks, depending on compilation flags etc.
Pavel Minaev
@eSKay, same thing as above applies. They usually don't, but your particular C++ compiler may have an option to insert them, with implementation-defined effect if they fail.
Pavel Minaev
@Pavel: I recall a presentation I went to on designing a crash-resistant C/C++ compiler for when not crashing was a must. It did fun stuff like handling memory leaks by overwriting existing memory in the code and using modulo operations on array indexes instead of bounds checking. When testing the compiler on existing programs with crash bugs, they found it mostly worked.
Brian
+2  A: 

a doesn't contain a null terminated string (extra initializers for fixed size arrays - such as the null terminator in "hello" - are discarded), so the behaviour when a pointer to that array is passed to puts is undefined.

Charles Bailey
Or more specifically, it'll compile but it'll do weird things when you run it.
Brendan Long
This doesn't answer the question, which was *why* this compiles in the first place, not how it behaves.
Edan Maor
@Edan Maor: "extra initializers for fixed size arrays are discarded"
Charles Bailey
It compiles because it's perfectly legal C++ code. C++ code isn't required to work ;)
Brendan Long
I think I've explained the error; the error is passing a parameter than isn't a null-terminated string to `puts`. The initialization of the `char` array is valid, even if dubious.
Charles Bailey
@Charles: OK you're right, but maybe you could emphasize that (and maybe explain why C lets you get away with this particular thing: is it ever *not* a bug?)
Edan Maor
It does work just fine, too. It's not illegal to have a non-null-terminated char array in C++. You shouldn't treat it as string (which is, by convention, a null-terminated char array), but that's an altogether different story.
Pavel Minaev
A: 

"hello" string is kept in read-only memory with 0 in the end. "a" points to this string, this is why the program may work correctly. But I think that generally this is undefined behavior. It is necessary to see Assembly code generated by compiler to see what happens exactly. If you want to get junk output in this situation, try:

char a[5] = {'h', 'e', 'l', 'l', 'o'}
Alex Farber
@Alex Farber: I am still getting a `hello` as output!
Lazer
It is necessary to test both in Debug and Release configurations. Again, the real answer is in Assembly code.
Alex Farber
+2  A: 

In my experience, a lot of compilers will let you get away with compiling this. It will usually crash at runtime, though (because you don't have a null terminator).

pm_2
It will crash only if puts() ends up reading memory not owned by the program, but it may not crash if the memory beyond the array does contain a null character. This is important to understand because problems like this could lead to segmentation faults that don't happen every time the program is run.
Kjir
+1  A: 

C char array initialization includes the terminating null only if there is room or if the array dimensions are not specified.

Fred
A: 

You need 6 characters to store "hello" as a null terminated string. But char arrays are not constrained to store nul terminated string, you may need the array for another purpose and forcing an additional nul character in those cases would be pointless.

AProgrammer
A: 

The C compiler you are using does not check that the string literal fits to the char array. You need 6 characters in the array to fit the literal "Hello" since the literal includes a terminating zero. Modern compilers, such as Visual C++ 2010 do check these things and give you and error.

Kyberias
+1  A: 

The C compiler allows you to explicitly ask for no null terminator.

char a[] = "Hello";  /* adds a terminator implicitly */
char a[6] = "Hello"; /* adds a terminator implicitly */
char a[5] = "Hello"; /* skips it */

Any value smaller than 5 results in an error.

As for why - one possibility is that your strings are of a fixed size, or are being used as buffers of byte values. In these cases you do not need a null terminator.

Best practice is to use char a[] so the compiler can set it to the correct value (including terminator) automatically.

rjh