19

Why does printf print a space instead of stopping when I use the NULL character from the ASCII table? This is what I mean:

printf("Hello%c, world", 0); //Hello , world
printf("Hello%c, world", '\0'); //Hello , world

Only when I put the escape character in the string itself printf stops the string:

printf("Hello\0, world"); //Hello

I tried this on Windows 8, Windows 10 (using cygwin, MinGW, Netbeans, Code::Blocks), XUbuntu, it's all the same.

Where is the problem? I asked one of my friends, but he said that he has no such problem, that all three examples executed the same way.

Numeri
  • 1,027
  • 4
  • 14
  • 32
sofia.bul
  • 219
  • 2
  • 6
  • Why do you think the first 2 should print only Hello? [c++ example](http://coliru.stacked-crooked.com/a/1d7e28cf27e49f71) – rozina Oct 22 '15 at 10:44
  • 2
    Because, 0 is the number of NULL/zero terminator in ASCII table, and its escaping character equivalent is '\0'. – sofia.bul Oct 22 '15 at 10:46
  • 2
    @rozina, because `'\0'` is the null terminator character? – David Ranieri Oct 22 '15 at 10:47
  • @AlterMann But OP told printf() to print a single character. What output do you expect for that? His implementation chose a white space. The c++ example I posted chose to ignore it. I don't know why it should terminate the input string, which obviously ends after the word "world". – rozina Oct 22 '15 at 10:49
  • @rozina Do you know how null-terminated strings work? – cadaniluk Oct 22 '15 at 10:49
  • @cad Yes I do. The only null terminated string in the OP code I see is "Hello%c, world". Null comes after 'd'. – rozina Oct 22 '15 at 10:50
  • This question is equally applicable to both C++ and C, both have the same `printf` specification, so I think it should have both tags. – Emil Laine Oct 22 '15 at 10:50
  • @rozina I put the both tags but I was suggested to chose only one language and I chose c. – sofia.bul Oct 22 '15 at 10:52
  • That would be the better choice if you couldn't tag both, because no one uses `printf` in C++. – Emil Laine Oct 22 '15 at 10:53
  • 1
    @rozina My question is principal. I am new in c and programming at all and I am trying to understand the logic and programming and C in particular. So don't wonder that I chose such meaningless example. The point is that according to my trainer all three examples must print the same output but they dont. – sofia.bul Oct 22 '15 at 10:54
  • @zenith It is still used (embedded software for example). – rozina Oct 22 '15 at 10:54
  • You are taking a dependency on a printf() implementation detail. The low-level terminal output function requires the length of the string as an argument. So what matters is whether your printf() implementation calculates the length of the string *after* formatting or *while* formatting. The latter is not uncommon. – Hans Passant Oct 22 '15 at 10:55
  • 1
    @rozina, I know that, I'm just answering to your question: _Why do you think the first 2 should print only Hello?_ – David Ranieri Oct 22 '15 at 10:56
  • @rozina Yes of course. I meant virtually no one. – Emil Laine Oct 22 '15 at 10:56
  • I guess that this question is related to why `printf("%");` is wrong, while OTOH, `printf("%s", "%");` is correct. – Spikatrix Oct 22 '15 at 11:23
  • Show us your friend's **exact code** and we'll tell you where it is different from yours, or not. – Jens Oct 22 '15 at 11:31
  • First, there is no problem, this is expected behaviour. Second, what your friend sees depends on how his terminal handles `NUL`. I would be surprised, however, if he sees behaviour different from what you observe. – copper.hat Oct 22 '15 at 18:18

4 Answers4

25

printf("Hello\0, world"); uses its parameter as a C-string so it decodes it until it finds a NUL char, so it stops just after \0, ignoring what follows.

printf("Hello%c, world", 0); decodes its parameter (until it finds inside it a NUL char - i.e. after d), in the meanwhile it finds a %c, so it replaces it with the char given as parameter (whose ASCII code is NUL) and then send to the terminal a NUL char, and then continues.

Printf manual says:

These functions write the output under the control of a format string that specifies how subsequent arguments [...] are converted for output.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
6

You are taking a dependency on a printf() implementation detail. The low-level terminal output function requires the length of the string as an argument. There are two ways for printf() to do this.

The somewhat obvious way is to first format the string, then use strlen(). That's the one you hoped for.

But that's inefficient because it requires a double pass across the string buffer and appending 0. The other way to do it is track the formatted string length while substituting the fields, simply incrementing it for every appended character. Since it continues past the %c, you'll now get the larger length that includes everything past %c. What the terminal function does with the embedded 0 is an implementation detail as well, given that it is not a printable character. Seeing it substituted with a space is not uncommon.

Sane way to go about this is to not rely on implementation details.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
1
printf("Hello%c, world", 0); //Hello , world
printf("Hello%c, world", '\0'); //Hello , world

In both of these cases, you're trying to print out the character value corresponding to character code 0, which is not a printable character. I haven't found chapter and verse on it, but I suspect the behavior of trying to print a nul character value is unspecified or maybe even undefined. Either way, I would not expect it to be treated as a string terminator in this case.

printf("Hello\0, world"); //Hello

In this case, the nul character is part of the string constant and is interpreted by the compiler as a string terminator.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • NUL char is defined as a kind NOP for output. – Jean-Baptiste Yunès Oct 22 '15 at 13:15
  • 1
    @Jean-BaptisteYunès: Chapter and verse? I couldn't find any definitive language in the standard, but searching a pdf on an iPad is kind of a pain in the ass. – John Bode Oct 22 '15 at 13:27
  • ASCII standard. **7.24** **NUL** (**NULL**). A control character used to accomplish media-fill or time-fill. NUL characters may be inserted into or removed from a stream of data without affecting the information content of that stream, but such action may affect the information layout and/or the control of equipment. – Jean-Baptiste Yunès Oct 22 '15 at 13:39
  • @Jean-BaptisteYunès: What about non-ASCII implementations? I was looking for language in the [C standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) describing what should happen if you tried to print a null character using `%c`, and I can't find any. This leads me to think that the behavior is undefined, and any result is possible. – John Bode Oct 22 '15 at 14:48
  • 1
    @JohnBode The C standard only covers ... well, the C language. Printing a character has nothing to do with the language, and everything to do with the *device* on which this character will be printed (and that's what the ASCII standard covers). If we follow your logic, printing *any* character would be "undefined behaviour". – Maël Nison Oct 22 '15 at 16:12
  • 1
    @MaëlNison: On the contrary, 5.2.2 describes character display semantics, including the intended behavior of non-graphical control characters (alert, form feed, line feed, etc.). "The intent of writing a printing character (as defined by the `isprint` function) to a display device is to display a graphic representation of that character at the active position and then advance the active position to the next position on the current line." The null character is not a printing character, and has no corresponding graphical representation. I *think* the behavior is undefined, but I'm not sure. – John Bode Oct 22 '15 at 16:39
0

In short: %c means to print a character, so printf print the NUL character which value is 0. NUL is a non-printing characters. So we can only see a space there.

"Hello\0, world" is a string literal, the result of strlen("Hello\0, world") is 5. So printf will print the result "Hello".

You can see more on website cppreference: string literal

A character string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in "xyz". The null character ('\0') is always appended to the string literal, thus, a string literal "Hello" is a const char[6] holding the characters 'H', 'e','l','l','0', and '\0'. If a string literal has embedded null characters, it represents an array which contains more than one string.

Jack47
  • 194
  • 1
  • 8