From the C Standard (7.21.6.1 The fprintf function, the same is valid for printf)
s If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.273)
Characters from the array are written up to (but not including) the terminating null character. If the precision is specified, no more
than that many bytes are written. If the precision is not specified
or is greater than the size of the array, the array shall contain a
null character.
and
9 If a conversion specification is invalid, the behavior is
undefined. If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
So the conversion specification %s
expects that the used character array as the corresponding argument contains the terminating null character '\0'
. Otherwise the behavior is undefined because the function tries to access the content of memory outside the character array until the terminating null character is encountered.
Answering your question
I expected for error but which didn't happen. Instead the array was
printed with some other characters. Why is that?
I can say that undefined behavior means that anything can occur. In this particular case the function outputted some redundant symbols below the character array until the terminating null character was encountered. In other cases a program can be abruptly terminated.
Instead you could write
printf("%.*s", ( int )sizeof( x ), x );
and according to the first quote from the C Standard "if the precision is specified, no more than that many bytes are written".