0

Why is it that the following:

#include <stdio.h>

int main(int argc, char *argv[])
{
     char array[3] = {'1', '2', '3'};
     printf("%s\n", array);

     return 0;
}

produces 1238À§Wˇ ("123" + some random chars) as expected, while the same code with:

int main(void)

instead of argc, argv produces: 123 (despite there being no room for the null byte).

How is it that the lack of room for a null byte in array with void doesn't seem to matter?

toxefa
  • 283
  • 2
  • 10
  • 9
    One undefined behavior may differ from another one :). BTW, does `char array[3] = { '1', '2', '3', '4' };` really compile? – AlexD Jan 12 '16 at 00:01
  • Did you mean `char array[3] = {'1', '2', '3'};`? You didn't even allocate enough space for the `'4'`. That's a constraint violation; a compiler could just treat it as a fatal error. (gcc, unfortunately, merely warns about it by default.) – Keith Thompson Jan 12 '16 at 00:02
  • What did you pass for the command line args? – lost_in_the_source Jan 12 '16 at 00:03
  • i'm totally guessing here but it could be that with those arguments, it allocates more memory for itself and when you print, it gives you that string. Without those arguments, it knows exactly how much memory to allocate with `char array[3]` this gives you only 123. – RisingSun Jan 12 '16 at 00:03
  • whoops @KeithThompson, typo - have ammended. – toxefa Jan 12 '16 at 00:04
  • 2
    So you try to four bytes into a 3-byte array, don't bother to NUL-terminate it, then wonder why it prints garbage when printed as a string? It's undefined behavior. – Andrew Henle Jan 12 '16 at 00:04
  • @AndrewHenle No. As you'll see above, I would expect it to print garbage but found it prints fine without `argv` and `argc` passed to `main()`. I would expect the lack of NUL termination to always result in problems. – toxefa Jan 12 '16 at 00:06
  • @py4on What compiler are you using. With 'gcc 5.3.0' they both behave the same – PeCosta Jan 12 '16 at 00:06
  • When you edit your questions then new viewers are lost. Nevertheless, one of your premises is incorrect: argv is, in fact, allocated correctly before your program ever runs. – Dúthomhas Jan 12 '16 at 00:08
  • @AlexD It's undefined if one undefined behavior differs from another one. :) :) – bolov Jan 12 '16 at 00:09
  • @PeCosta Am using `cc` – toxefa Jan 12 '16 at 00:10
  • One of the possible outcomes of undefined behavior is that the code seems to work. In other words, the statement *"I would expect the lack of NUL termination to always result in problems"* is technically incorrect. The correct statement is *"The lack of NUL termination may result in problems"*. – user3386109 Jan 12 '16 at 00:10
  • To put it another way, your code exhibits undefined behavior, and you know it exhibits undefined behavior, so no further analysis is warranted, useful, or productive, i.e. @AndrewHenle is right. – user3386109 Jan 12 '16 at 00:13
  • The lack of NUL-termination results in undefined behavior. This behavior may be indistinguishable from defined behavior. Or the compiler could choose to ransom your system for bitcoins. Or something in between. More seriously, it's luck of the draw if the byte following `array` happens to be a NUL. – John Hascall Jan 12 '16 at 00:14
  • 1
    [Does “Undefined Behavior” really permit *anything* to happen?](https://stackoverflow.com/questions/32132574/does-undefined-behavior-really-permit-anything-to-happen) – kaylum Jan 12 '16 at 00:15
  • 1
    Using `main(void)` **seems** to fix the problem, but it doesn't really. With another compiler, another machine, another target architecture, it could lead to the "expected" problem. The important thing is that you don't conclude that using no arguments for `main` solves the problem, because it would be wrong. If you want to try on ideone.com you'll see that in both cases it doesn't actually output anything, not even `123` (though I have to admit I don't understand why) – Fabio says Reinstate Monica Jan 12 '16 at 00:18

2 Answers2

3

You're not providing the end-of-string (EOS) zero byte, so printf keeps going until it [just happens] to find one (i.e. the garbage characters).

Any of the following would work:

char array[4] = { '1', '2', '3', '\0' };
char array[4] = { '1', '2', '3' };
char array[4] = "123";
char array[] = { '1', '2', '3', '\0' };
char array[] = "123";
char *array = "123";
fuz
  • 88,405
  • 25
  • 200
  • 352
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
2

When you do this:

char array[3] = {'1', '2', '3'};
printf("%s\n", array);

you are invoking undefined behavior, because the character array is not NUL terminated. You might get "123", or nothing at all, or somethink like that, or it might vary depending on any arbitrary conditions.

In your specific case, just an educated guess, after the local variable array it is probably the memory for the function arguments, and those happen to be argc and argv. Depending on the actual arguments to main and even the runtime values passed to the program, the bytes on thos memory positions will vary. And sometimes they will have to have a NUL byte at the proper place and affect the output of your program.

Anyway, my advice is not to overthink the cases of UB. They are best thought of as just undefined.

rodrigo
  • 94,151
  • 12
  • 143
  • 190