For some reason, adding \\n
to printf()
changes the behaviour of below code. The code without \\n
prints (null)
whereas t
Executing with no arguments argv[1]
shall be NULL
pointer. With argv[1]
being NULL
printf("%s", argv[1]);
will invoke undefined behavior.
The code has undefined behavior in both cases if the program is not given any command line arguments, so anything can happen.
Since you are curious (good for you!), here is a potential explanation for what you observe:
printf("%s\n", argv[1]);
can be optimized by the compiler into puts(argv[1]);
whereas printf("%s", argv[1]);
still invokes printf()
.
some implementations of printf
accept a null pointer as an argument for the %s
conversion, hence the output (null)
.
puts()
has undefined behavior for a null pointer, in your case a segmentation fault.
Try compiling both without any optimization (-O0
) and see if you get (null)
output with and without the \n
.
You can play with godbolt's compiler explorer and see how clang
changes behavior with -O0, but not gcc
.
Both are undefined behavior, so an answer could stop right here.
But there's at least an explanation for the output of (null)
. This is an extension in glibc
(the GNU C library). Passing 0
for %s
in printf()
is considered undefined in the C standard and therefore could very well result in a crash. The developers of glibc
decided to do something meaningful instead.
The reason the second crashes nevertheless is that with the newline, the compiler decides to optimize: Instead of printf("%s\n", argv[1])
, it executes puts(argv[1])
, which is semantically equivalent according to the C standard, therefore an allowed optimization. But glibc
s "(null)-trick" is only implemented in printf()
.
There's another undefined behavior in your program: You potentially access argv
out of bounds. There's no guarantee what value you will find at argv[i]
when i > argc
. There's a slight chance argc
could be 0, so you could experience anything else as well.