-5

Since a C character array requires a null terminator, the following code prints four a s and some garbage characters.

char y[4] = {'a', 'a', 'a', 'a'};
printf("y = %s\n", y);

Output:

y = aaaa�

However, the following code produces no garbage characters.

char y[4] = {'a', 'a', 'a', 'a'};
char z[4] = {'b', 'b', 'b'};

printf("y = %s\n", y); 
printf("z = %s\n", z);

Output:

y = aaaa
z = bbb

I understand that the fourth character of z is automatically initialized with a null terminator. Also I guess that y and z get allocated next to each other in the memory.

But how does C correctly print just 4 a s in this case and not in the former? Does it identify that the next byte is already allocated to another variable, so it should stop printing anymore?

thameera
  • 9,168
  • 9
  • 37
  • 38
  • *How does C identify end of character array when there's no null terminator?* - It doesn't. It's your luck that identified it :) – Maroun Mar 31 '13 at 07:11
  • 2
    I have a feeling this is just a coincidence. Maybe it will print some garbage characters after the `a`s, maybe not. Could just depend on how the compiler compiled the code and how the stack looked at runtime. – Scott Olson Mar 31 '13 at 07:13
  • 2
    I propose that C compilers should, by default, fill the stack and heap with garbage (preferably randomized). This will ensure that programmers properly understand the ramifications of undefined behaviour, and vow never to commit it. (Then we can have the magic --dont-randomize-stuff-i-know-what-i-am-doing flag to turn off that particular anti-optimization). – nneonneo Mar 31 '13 at 07:40

3 Answers3

6

printf("y = %s\n", y); is, in this case, undefined behaviour. In other words, you got lucky -- maybe you printed some invisible characters before hitting a NUL, maybe there's a zero after the array because of stack alignment, maybe the stars are right.


I don't usually elaborate on "it's UB, don't touch", but I feel oddly compelled to.

Look, here's your program:

#include <stdio.h>
int main() {
    char y[4] = {'a', 'a', 'a', 'a'};
    char z[4] = {'b', 'b', 'b'};

    printf("y = %s\n", y); 
    printf("z = %s\n", z);
}

And now I'm going to compile it with my special compiler flags:

$ cc -O3 so15727258.c -o so15727258 -fstack-protector-all -Wall

And run it:

$ ./so15727258
y = aaaa?>A??0F
z = bbb

Whoops, haha, that's total garbage. Better yet, it's randomized garbage because of the stack protector, so it's not even (simply) deterministic. Woot!


Still not convinced? Were the special compiler flags too weird for you? Try

#include <stdio.h>

int bar() {
    char x[4096];
}

int foo() {
    char y[4] = {'a', 'a', 'a', 'a'};
    char z[4] = {'b', 'b', 'b'};
    printf("y = %s\n", y); 
    printf("z = %s\n", z);
}

int main() {
    bar();
    foo();
}

Compile it:

$ cc so15727258.c -o so15727258 -Wall

And run it:

$ ./so15727258
y = aaaa?????ic?
z = bbb

Still total garbage! Just remember -- these examples are all illustrative. Of course this is undefined behaviour, so you might get some totally different result, and come back here and tell me "but XYZ works". That's the very definition of undefined behaviour.

nneonneo
  • 171,345
  • 36
  • 312
  • 383
2

Your program exhibits undefined behavior, even if it appears to work. Strings must be terminated with '\0' for most string operations and for printing.

If you wonder how it's so that it still appears to work in some cases, there may be zero bytes between objects (or in adjacent objects) and they may serve as string terminators.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
0

It doesn't you just got lucky... You can test it. Print the memory content of the byte just after the array. I can promise you with my eyes closed it's zero...

stdcall
  • 27,613
  • 18
  • 81
  • 125
  • So you're saying it's zero no matter what system I'm on? BZZZT, wrong answer. – nneonneo Mar 31 '13 at 07:19
  • No. I'm saying that if print printed 4 characters. Then and only then the next byte is zero. Doesn't make a difference which OS it is as long that it uses POSIX printf – stdcall Mar 31 '13 at 07:22