C - Printing null character using %c in nested printf statement - c

Why both inner printf() functions are working different even the printing value is same for both functions ?
Here is the code -:
#include<stdio.h>
int main()
{
char ch = '\0';
printf("%d",printf("%c", ch)) ;
// This line will print 1.
printf("%d",printf("\0")) ;
// This line will print 0.
return 0;
}

printf("%d", printf("%c", '\0'));
Why this line prints 1?
The value '\0' is one single character, which "%c" sends th stdout (though you can't see it).
printf("%d", printf("%s", "\0"));
Why this line prints 0?
The string "\0" has two characters in it: the literal '\0' and the implied '\0'. None of them are printed with "%s", the first zero terminates the string. The string "foo" has 4 characters: the 3 literal ones and the implied '\0'

Referring to man page of printf
man 3 printf
printf returns the following
RETURN VALUE
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).
So it does not return the count of null bytes.
In the first printf you are explicitly telling to print 1 character, so the output is 1. In the second printf there is nothing to print or NULL. So the output is 0

#include<stdio.h>
int main()
{
char ch = '\0';
printf("%d",printf("%c", ch)) ;
The inner call to printf() prints a null character (you don't see it) and returns 1 as the number of characters printed, which is then printed as the string 1 (you get a null plus a digit 1).
// This line will print 1.
printf("%d",printf("\0")) ;
In this case, you supply a string literal ended in two consecutive null chars, which results on printing an empty string (literally "") and that results in passing to the second printf a 0 and the second printf prints it as the string 0.
// This line will print 0.
return 0;
}
So, you are wrong, in the first case you got a null character printed (a true \0 befpre tje 1. But a null is ignored by the terminal you are using and it doesn't show in your screen, while the second doesn't print anything·)
NOTE
Every C language string related function, explores the string to know how long it is, or when to stop the task it is doing. Putting more than the default string literal's last null char \0 does nothing but shorten the useful part of the string literal. If you try to print "Se está quemando la serrería\0... Duduap!!" or operate on it with any of the string related functions, you'll get the same result as if you had stopped before the first \0 character. So the string literal above is basically equivalent to just "Se está quemando la serrería"

They are working different because first inner printf is printing a character and that character is a null character which has length of 1. While in your second inner printf you are trying to print a string which only contains null character, but due to null character the string became empty with length 0. This is the reason why your first outer printf printed 1 and second outer printf printed 0.

Related

How does a null character behave in a char array in C?

I tried to reverse this char array with null characters in the middle and the end, without using string length. (original code)
#include <stdio.h>
#include <stdlib.h>
int main()
{
char string[4] ={'c', '\0', 's', '\0'};
printf("What do we love?\n");
printf("Yes, we love:");
for(int i=3; i>=0; i--){
printf("%d", string[i]);
}
return 0;
}
I expected the output to display nothing. But I got the reverse of the array with whitespaces at the places where I’m guessing are the null characters? (output)
Bcoz I have tried using %d too instead of %c and found that those spaces apparently do have the ascii value of 0. (code with slight change + output + ascii table)
So, does this mean that a loop will not always treat a null character in a char array as an indicator of termination? Does this also mean null characters, which automatically get appended on the empty spaces of a char array actually, get printed as spaces in display, but we just say that it prints nothing in the output after it encounters null character only coz we see 'nothing' on display with most codes?
A null byte is used in a char array to designate the end of a string. Functions that operate on strings such as strcpy, strcmp, and the %s format specifier for printf, will look for a null byte to find the end of a string.
You're not treating string as a string, but as just an array of char. So it doesn't matter whether or not a particular element of the array has the value 0 as you're not treating that value as special in any way. You're just printing the decimal value of each of the elements of the array.

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'?
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.
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.
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 '

printing string in c using a pointer

I was just printing some characters in C.
I have declared char c and assigned its characters.
then using a for loop i try to print the characters one by one.
I have used pointers, of course.
#include <stdio.h>
#include <string.h>
int main()
{
char c[4] = {"hia"};
int i;
for(i=0;i<4;i++)
{
printf(&c[i]);
}
return 0;
}
However when I compile my code using turbo, i get output "hiaiaa" instead of "hia"! What am i doing wrong here?
Your printf() call is broken. You are using the string (from the point you specify) as the formatting string. This will not print single characters. Instead each call will print from where its formatting string starts, to end of the string.
This means the first call will print all of c, the next will print from c[1] and onwards, and so on. Not at all what you wanted.
If you want to print single characters, use the %c format specifier:
printf("%c", c[i]);
No pointer necessary, since the character is passed by value to printf().
This is what happened in your loop:
0. hia
1. ia
2. a
3. \0
However, you want to print exactly one char at a time, not a null terminated string, so you should pass it as char not a char*:
printf( "%c", c[i] )
Also, you are looping four times, but string length is just three. You should use:
for( i = 0; i < strlen( c ); i++ )
...
The printf function have an char* as first argument, that's correct. However, it prints a string (that is, a zero-terminated sequence of char) so it will always do that.
If you want to print one character at a time, then you have to use that format, like in:
printf("%c\n", c[i]);
You also have another problem, and that is that you try to print the zero terminator as well. This character is not printable so will not show. Use e.g. i < strlen(c) as the loop condition to overcome this.
Also, instead of printing character-by-character, print it all as one string:
printf("%s\n", c);
1) For loop size should i<3 , not i<4 (i=3 refers to the null character at the end of the string)
2) use printf("%c",c[i]);
Explanation of what you're seeing: In each loop, printf is printing a null-terminated string. This string starts in every loop one char later inside your array.
How it should be done, depends on what you're intending. If you want to print the string char by char via pointer you may use:
char *p=&c[0];
while (*p) {
printf("%c", *p);
p++;
}
Your question is to print string using pointer. You could use
printf("%s", c);
or character by character as (include library string.h for this)
for(i=0;i<strlen(c);i++)
{
printf("%c", c[i]);
}
in C strings are stored as character arrays and are terminated by a zero-value, so called zero-terminated strings. Btw, this is why you have to make the array size of 4 for thee real chars.
In your example, you are passing pointers th each char to the printf function and printf prints the strings from your pointer to the next null-value . The 1st pass prints "hia", the 2nd ia and the 3rd a.
To print a single char in each pass, you have to use
printf ("%c", c[i]);
Your loop will call printf with the following parameter:
printf("hia"); // first loop iteration
printf("ia"); // second loop iteration
printf("a"); // third loop iteration
printf(""); // fourth loop iteration
You probably meant to print one character at a time:
for(i=0;i<3;i++) // No need to print the string termination character.
{
printf("%c", c[i]); // "%c" is the printf format code to print a single character
}

How does this loop end?

code example like this:
#include<stdio.h>
void main()
{
char *s={"abcd"};
do {
printf("%d\n",++s);
} while(*s);
}
Where does the pointer s point when the loop do ends?How does it work?
In C, zero is equivalent to false. So when *s points to the terminator character in the string (a zero), the loop stops.
"abcd" is stored in memory in 5 consecutive bytes: 'a' 'b' 'c' 'd' '\0'.
The last byte, zero, terminates the loop since zero is false in C.
First of all, you should not use %d for formatting a pointer, it is for integers, not for pointers. Use %p instead.
This line-
char *s={"abcd"};
initializes the string with '\0' as the last character.
Your programs loops through each character (from 2nd to last) of the string an prints the address of where they are stored in the memory. Since it is a do-while loop, the condition checking is done after the execution of the body of the loop.
NOTE: It does NOT print the address of the first character because-
printf("%d\n",++s);
this line (due to prefix increment) increments the pointer to the next character before passing its value to printf. So when the body of the loop is executed for the first time, the address of the second character(b) is printed.
Now the condition part of the loop checks whether character at pointed by s (the character can be referred to by *s) is non-zero.
As the string has '\0' as the last character (which has an integer value of 0), the loop terminates when it reaches the last character.
The output of your program (with %d changed to %p) will be something like but NOT exactly same as-
0x40061d
0x40061e
0x40061f
0x400620
Note that only 4 addresses are printed (from 'b' to '\0', the address of 'a' is not printed). To do that you should try this-
#include<stdio.h>
main()
{
char *s={"abcd"};
do {
printf("%p\n",s++);
} while(*s);
printf("%p\n", s); // to print the address of the '\0' character.
}

How to print a string with embedded nulls so that "(null)" is substituted for '\0'

I have a string I composed using memcpy() that (when expanded) looks like this:
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
I would like to print every character in the string, and if the character is null, print out "(null)" as a substitute for '\0'.
If I use a function like puts() or printf() it will just end at the first null and print out
AAAA
So how can I get it to print out the actual word "(null)" without it interpreting it as the end of the string?
You have to do that mapping yourself. If you want to, that is. In C, strings are null-terminated. So, if you use a formatted output function such as printf or puts and ask it to print a string (via the format specifier %s) it'd stop printing str as soon as it hits the first null. There is no null word in C. If you know exactly how many characters you have in str you might as well loop over them and print the characters out individually, substituting the 0 by your chosen mnemonic.
The draft says 7.21.6.1/8:
p The argument shall be a pointer to void. The value of the pointer is
converted to a sequence of printing characters, in an
implementation-defined manner.
However, the following:
$ cat null.c
#include <stdio.h>
int main() {
printf("%p\n", (void *)0);
}
produces:
00000000
on both gcc 4.6 and clang 3.2.
However, on digging deeper:
$ cat null.c
#include <stdio.h>
int main() {
printf("%s\n", (void *)0);
}
does indeed produce the desired output:
(null)
on both gcc and clang.
Note that the standard does not mandate this:
s If no l length modifier is present, the argument shall be a pointer
to the initial element of an array of character type.280) 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.
Relying on this behavior may lead to surprises!
Instead of printing the string with %s , you will have to come up with a for loop that checks a condition whther a given char in your char array is a \0 and then print the NULL
From C++ Reference on puts() (emphasis mine):
Writes the C string pointed by str to stdout and appends a newline
character ('\n'). The function begins copying from the address
specified (str) until it reaches the terminating null character
('\0'). This final null-character is not copied to stdout.
To process data such as you have, you'll need to know the length. From there, you can simply loop across the characters:
/* ugly example */
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
int len = ...; /* get the len somehow or know ahead of time */
for(int i = 0; i < len; ++i) {
if('\0' == str[i]) {
printf(" (null) ");
} else {
printf(" %c ", str[i]);
}
}
One of the key cornerstones of C is strings are terminated by '\0'. Everyone lives by that rule. so I suggest you not think of your string as a string but as an array of characters.
If you traverse the array and test for '\0', you can print "(null)" out in place of the character. Here is an example. Please note, your char * str was created either as a char array or on the stack using malloc. This code needs to know the actual buffer size.
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
int iStrSz = <str's actual buffer size>
int idx;
for(idx=0; idx<iStrSz; idx++)
{
if('\0' == *(str + idx)
{
sprintf("%s", "(null)");
}
else
{
putchar(*(str + idx));
}
}
printf("%s", "\n");

Resources