views:

670

answers:

7

I am a little confused by the following C code snippets:

printf("Peter string is %d bytes\n", sizeof("Peter")); // Peter string is 6 bytes

This tells me that when C compiles a string in double quotes, it will automatically add an extra byte for the null terminator.

printf("Hello '%s'\n", "Peter");

The printf function knows when to stop reading the string "Peter" because it reaches the null terminator, so ...

char myString[2][9] = {"123456789", "123456789" };
printf("myString: %s\n", myString[0]);

Here, printf prints all 18 characters because there's no null terminators (and they wouldn't fit without taking out the 9's). Does C not add the null terminator in a variable definition?

+18  A: 

Your string is [2][9]. Those [9] are ['1', '2', etc... '8', '9']. Because you only gave it room for 9 chars in the first array dimension, and because you used all 9, it has no room to place a '\0' character. redefine your char array:

char string[2][10] = {"123456789", "123456789"};

And it should work.

Chris Lutz
+1 for beating me to it
Sean Bright
+2  A: 

Sure it does, you just aren't leaving enough room for the '\0' byte. Making it:

char string[2][10] = { "123456789", "123456789" };

Will work as you expect (will just print 9 characters).

Sean Bright
Is there a reason why the compiler doesn't warn that there isn't enough room for the 0 byte? I get a warning if I try to add another '9' that won't fit, but it doesn't seem to care about dropping the 0 byte?
too much php
A: 

Is there a reason why the compiler doesn't warn that there isn't enough room for the 0 byte? I get a warning if I try to add another '9' that won't fit, but it doesn't seem to care about dropping the 0 byte?

too much php
For the most part C assumes you know what you're doing and that when you say you want the who thing filled it trusts that that is what you mean; however, once you go beyond the allocated space, it knows you're being an idiot and warns you.
Aaron Maenpaa
Let's say you wanted to store 9 chars. Why should C include a null byte at the end for you. The null byte is only useful when that char array is used as a string.
geowa4
The compiler assumes that if you wanted just enough room to fit the whole string, you'd have done char x[] = "abc"; instead of char x[3] = "abc"; The former would automatically and implicitly make it a char x[4].
Chris Young
A: 

The '\0' byte isn't it's problem. Most of the time, if you have this:

char code[9] = "123456789";

The next byte will be off the edge of the variable, but will be unused memory, and will most likely be 0 (unless you malloc() and don't set the values before using them). So most of the time it works, even if it's bad for you.

If you're using gcc, you might also want to use the -Wall flag, or one of the other (million) warning flags. This might help (not sure).

Chris Lutz
+2  A: 

If you tell C that an array is a given size, C cannot make the array any larger. It would be disobeying you if it did so! Remember that not every char array contains a null terminated string. Sometimes the array (as used) is truly an array of (individual) char. The compiler doesn't know what you are doing and cannot read your mind.

This is why C allows you to initialize a char array where the null terminator won't fit but everything else will. Try your example with a string one byte longer and the compiler will complain.

Note that your example will compile but will not do what you expect, as the strings are not null terminated (unless your compiler is doing something unusual). With GCC, running your example, I see the string I should, followed by garbage.

Eddie
+1 for pointing out that garbage should very likely follow, instead of nicely 18 characters.
PolyThinker
+1  A: 

Alterenatively, you can use:

char* myString[2] = {"123456789", "123456789" };

Like this, the initializer computes the right size for your null terminated strings.

Sébastien RoccaSerra
+2  A: 

C allows unterminated strings, C++ does not.

C allows character arrays to be initialized with string constants. It also allows a string constant initializer to contain exactly one more character than the array it initializes, i.e., the implicit terminating null character of the string may be ignored. For example:

char  name1[] =  "Harry";   // Array of 6 char

char  name2[6] = "Harry";   // Array of 6 char

char  name3[] =  { 'H', 'a', 'r', 'r', 'y', '\0' };
                            // Same as 'name1' initialization

char  name4[5] = "Harry";   // Array of 5 char, no null char

C++ also allows character arrays to be initialized with string constants, but always includes the terminating null character in the initialization. Thus the last initializer (name4) in the example above is invalid in C++.

Alex B