'ASCII value = 0 and '\0'

I have read this post. But when I tried:

  printf("before null %c after null\n", 0);  // (ASCII=0) != '\0' ??

instead of getting:

before null 

I got:

before null   after null

So my question is: Is ASCII value 0 actually equal to '\0'?



Solution 1:[1]

Is ASCII value 0 actually equal to \0?

Yes


The differences in how the strings are stored in memory and handled by functions like printf() are important.

"before null %c after null\n"
"before null \0 after null\n"

Both are stored in memory with an implicit \0 terminator at the end. The fact that the second has an explicit \0 character in the middle changes things.

printf() will scan the string until "the end", printing components as it goes... in C "the end" typically means until the first \0 / nul character.

With the first variant, printf() copies characters to the output until it reaches the %c directive, at which point it looks at the arguments that were given to the function... it might find that you gave '\0', or it might find that you gave '+' - either way, it copies this to the output. It'll then continue copying characters to the output, seeking "the end" of the string.

With the second variant, printf() will start copying characters to the output, will find "the end" (denoted by the \0), and stop.

If you were to use snprintf(), then the results / outputs would contain the following: (again, with implicit \0 termination)

"before null \0 after null\n"
"before null "

If you were to subsequently print both of these, they would look the same, but the memory content would be different.

However, the output of printf() is the terminal (or a file)... what happens for \0 depends on your terminal emulator... it might simply not be shown, it might be displayed as a space, or it may have a funny box symbol...

The important thing to note, is that this occurs at run time - not compile time.

Solution 2:[2]

That's because printf is NOT actually replacing "Hello %s", "World" with "Hello World" then print. No. It does not concatenate.

Rather, it actually prints each character alone in order, and when it encounters an argument, it starting printing each character from it directly too without concatenating.

If you ever tried to print a single null character using putchar(), You'd notice that it prints a space instead, that's why printf prints a space too based on it. (Note that It'll print nothing on other systems like Linux).

Sample code of how printf actually work.


const char * x;
// while the current char != '\0'
while (*format)
{
    // if the current char == '%'
    if (*format == '%')
    {
        // increment the pointer so we can point to the next char and skip printing '%'
        switch (*(++format)) // then switch that next char (specifier).
        {
        case 'c':
            putchar(va_arg(args, char)); // if the argument is null, then it's putchar(0);
            break;
        case 's':
            // regular operation of printing a string argument.
            x = va_arg(args, const char*);
            while (*x) putchar(*x++);
            break;
        }
        // skips the format specifier so we don't print it (e.g 's', 'c'..)
        *format++;
    }
    // else: isn't a format specfier.
    else
       // print the current char (pointer) of the original string
        putchar(*format++); // increments it for the next operation.
}
va_end(args);

So returning to your question, It will print each character and when it comes to the argument 0 which is null, putchar() will either put a space or nothing based on your system.

You can say that printf arguments don't really have any relationship with the original string to terminate it, they don't know each other. Like when you printf("Hello %s, from SO!", "World");, "World" is actually terminated at the end with \0, but it will terminate just itself, not the other , from SO!.

And Yes, 0 is '\0'. they're the same character.

Solution 3:[3]

printf will not terminate the printf format-string at that character position for the %c format-specifier when given values 0 or '\0'. Instead, the terminal output for the nul will generally be a placeholder (e.g. a space or the like)

However you can insert a nul into the string and then output the string using the %s format-specifier and see that in fact decimal 0 is actually the ASCII value for the equivalent ASCII character '\0' and will terminate the string at the point of the nul-character (see: www.ASCIItable.com), e.g.

#include <stdio.h>

#define FMT "before null %c after null\n"

int main (void) {

    char buf[sizeof FMT * 2];

    puts (FMT);

    sprintf (buf, FMT, 0);
    printf ("using 0 : '%s'", buf);
    putchar ('\n');

    sprintf (buf, FMT, '\0');
    printf ("using \\0: '%s'", buf);
    putchar ('\n');

    return 0;
}

Example Use/Output

$ ./bin/str_printf_null
before null %c after null

using 0 : 'before null '
using \0: 'before null '

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3