How to understand the behaviour of printf statement in C? - c

I have come across two C aptitude questions.
main()
{
int x=4,y,z;
y=--x;
z=x--;
printf("\n%d %d %d",x,y,z);
}
Output: 2 3 3 (it is printed left to right)
main()
{
int k=35;
printf("\n%d %d %d",k==35,k=50,k>40);
}
Output: 0 50 0 (it is printed right to left)
Why is it so? I have seen so many similar answers on Stack Overflow similar to this. People answer this is undefined behaviour, but if this is asked in interviews, how should one answer them?

The order of the evaluation of the arguments to any function in C is not in any particular order. It looks like the platform / compiler you are being asked about is probably evaluating the functions arguments right-to-left, which would print out the result you obtained, but the C standard says you do not know the order, so what is shown here is undefined behavior and would almost certainly obtain different results on a different compiler or platform.
Note, in your function, all the variable values are assigned before calling printf() - while in your main(), the values are being assigned to the variable in printf()'s argument list.

Yes, you need to read the documentation of printf. Read it carefully and several times.
You should compile with all warnings and debug info, i.e. using gcc -Wall -Wextra -g with GCC. Improve your code to get no warnings. Then use the gdb debugger to understand the behavior of your program.
On the second example (where I added the missing but mandatory #include <stdio.h>) GCC 8.1 gives on Linux/x86-64/Debian:
% gcc -Wall -Wextra -g m.c -o myprog
m.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main()
^~~~
m.c: In function ‘main’:
m.c:6:29: warning: operation on ‘k’ may be undefined [-Wsequence-point]
printf("\n%d %d %d",k==35,k=50,k>40);
~^~~
m.c:6:29: warning: operation on ‘k’ may be undefined [-Wsequence-point]
Also, as explained by John's H answer the order of evaluation of arguments is undefined (and the compiler gives some clue). A good way to think of it is to believe it is random and could dynamically change (but few implementations behave like that), and to write your source code in such way that won't change the intended behavior of your program.
In
printf("\n%d %d %d",k==35,k=50,k>40);
// ^
you have an assignment operator. So k is changing. But you don't know exactly when (it could happen after or before the k==35 and k>40 comparisons). So you have undefined behavior, be very scared!
At last, stdout is often buffered (see setvbuf(3) & stdio(3) for more) and usually line buffered. So the buffer could be flushed by the \n which you'll better place at the end of the format control string. Otherwise, ensure flushing by calling fflush(3).

From the C standard C99, section 6.5
The grouping of operators and operands is indicated by the syntax. 74)
Except as specified later (for the function-call () , && , || , ?:
,and comma operators), the order of e valuation of sube xpressions and
the order in which side ef fects tak ep lace are both unspecified.
So C standard doesn't say anything like that the function argument are solved from right to left & printed from left to right.
case 1 :- The statement y=--x; results in y=3 and x=3. when the expression z=x--; is performed. After this x=2 and z=3. Finally when the printf statement executed
printf("\n%d %d %d",x,y,z);
it prints 2 3 3.
Case 2 :- Here x=35 and when printf statement executes
printf("\n%d %d %d",k==35, k=50, k>40);
| | | <---- R to L (in your machine, seems argument passed from R to L, but can't grantee same for other platform)
50==35 50 35>40
| | | ----> L to R
0 50 0
In between, the main() prototype you used is incorrect. It should be int main(void) { /*... */ } as specified in C standard here
The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any
names may be used, as they are local to the function in which they are
declared):
int main(int argc, char *argv[]) { /* ... */ }

Let's trace through the code.
Example 1:
main()
This is no longer correct (since 1999). main needs a return type: int main().
{
int x=4,y,z;
Here x = 4 whereas y and z are indeterminate.
y=--x;
--x decrements x (from 4 to 3) and returns the new value of x (3), which is then assigned to y. At the end we have x = 3, y = 3, and z still indeterminate.
z=x--;
x-- decrements x (from 3 to 2) and returns the old value of x (3), which is then assigned to z. At the end we have x = 2, y = 3, z = 3.
printf("\n%d %d %d",x,y,z);
Here we're calling printf, but the function is not declared. The code is missing #include <stdio.h>; without it, the behavior is undefined (because it's calling an undeclared varargs function). But let's assume <stdio.h> was included. Then:
This outputs x, y, z as 2 3 3. Note that the format string should be "%d %d %d\n"; in the C model, lines are terminated by '\n', so you should always have a '\n' at the end.
}
Example 2:
main()
Same issue, should be int main() and #include <stdio.h> is missing.
{
int k=35;
Now k = 35.
printf("\n%d %d %d",k==35,k=50,k>40);
This is just broken. Function arguments can be evaluated in any order. In particular, the assignment to k (k = 50) and the comparisons (k == 35, k > 40) are not sequenced relative to each other, which means this piece of code has undefined behavior. You're not allowed to modify a variable while at the same time reading from it.
}
People answer this is undefined behaviour, but if this is asked in interviews, how should one answer them?
Tell them "this is undefined behavior". That's the correct answer. The example above is not required to produce any output. It could print 1 2 3, but it also could print hello!, or go into an infinite loop, or crash, or delete all of your files.
As far as the C standard is concerned, the code is simply meaningless.
(What happens on any particular platform is highly dependent on your compiler, the exact version of the compiler, any optimization options used, etc.)

I have seen so many similar answers on Stack Overflow similar to this.
People answer this is undefined behaviour,
And that's quite often the only correct answer.
but if this is asked in interviews, how should one answer them?
If your interviewer truly knows C, but chooses to ask this sort of question, it can be thought of as a trick question. They might seem to be expecting an answer like "1 50 1", but really they do expect the correct answer, which is, "It's undefined."
So if I were asked this question, I would give the interviewer a look suggesting "I can't believe you're asking me this", but then say, confidently, "It's undefined."
If the interviewer doesn't realize it's undefined, you have somewhat of a problem, but that's a human psychology and interview strategy question, not a C programming question, so I think I'll avoid delving into it further.

Related

why the output in the terminal is different when i put Prefix -- and a-1

#include <stdio.h>
int sum(int a);
int main()
{
int a;
printf("Enter a value: ");
scanf("%d", &a);
printf("%d", sum(a));
return 0;
}
int sum(int a)
{
if (a == 1)
{
return 1;
}
return a + sum(a - 1);
}
When the input is 5 the output is 15 (which is right),
but when the return is, return a + sum(--a);
(for the same input 5) the output is 11
The behaviour of a + sum(--a) is undefined. The compiler has a lot of freedom as to when and how often it reads a, and when and how often it modifies a. Avoid both reading and modifying the same variable in an expression.
When you wrote
a + sum(a - 1)
, a rough translation of that C code into English is:
"Take a plus the result of the sum function applied to the quantity a-1."
That makes sense, and it's just what you want.
If, on the other hand, you write
a + sum(--a)
, now what you're saying is,
"Take a plus the result of the sum function applied to, hang on a minute, I want to take the variable a minus 1 and assign it back to a and then, where was I, pass it to sum()."
Is that really what you want to do? Why would you want to modify a's value in the middle of calling sum()? You wouldn't want to do that, you don't need to do that, that has nothing to do with the problem of calling sum(a - 1). So don't write it that way. It's confusing to you and me, and what's worse, it's so confusing that the compiler can't figure it out, either. It's so confusing that it's undefined behavior, meaning that the compiler isn't even required to figure out what you mean, and the compiler is explicitly allowed to fall back and punt, and compile your program into something that doesn't work — which is precisely what you discovered when you tried it.
See the canonical SO question Why are these constructs using pre and post-increment undefined behavior? for much (much!) more on undefined expressions like these.

C function variable changing

I have a basic code to learn function call. But I did not understand something in this code. I got confused when I compare to with my answer and expected output.
My code is below:
#include <stdio.h>
void f(int a, int b, double c){
printf("%d \n", a);printf("%d \n", b);printf("%f \n", c);
}
int main(void){
int i = 0, x = 7;
float a = 2.25;
f (x=5, x-7, a);
printf("\n\n");
f (x = 6, x-7, a);
printf("\n\n");
printf("%d %d\n",i, i++ );
printf("%d %d\n",i, ++i );
return 0;
}
At the last 2 printf statements, My answer was as:
0 0
1 1
But the output as:
1 0
2 2
Can you explain why?
It is undefined behavior in C. It may vary as per the execution or many other things. The order of evaluation of function arguments are unspecified. You can never explain the behavior you see by any standard rule. It would have given different result when you run it in front of teacher in a different machine.
Better you write the code which avoids all these sort of ambiguity.
The example which is explicit about this from standard 6.5.2.2p12
In the function call
(*pf[f1()]) (f2(), f3() + f4())
the functions f1, f2, f3, and f4 may be called in any order. All side effects have to be
completed before the function pointed to by pf[f1()] is called.
Same way when you pass the arguments - their evaluation order may vary. And your example of printf is also another such example.
Check the slide from which you got to know about this - must be a slide one Undefined behavior
Can you explain why?
Because the compiler had calculated the arguments from right to left. It was allowed to do it either way, and it finally produced the code which did it like that. You know, it didn't want to die like Buridan's donkey ;-)
You may say that C compilers have no free will. Yes, they don't, but the generated code depends on many different things, such as compiler brand, version, command-line options etc. And C standard doesn't impose any limitations on C compilers in that particular case. So it's officially called "undefined behaviour". Just never do this.

Why a syntax like "a=b--- // a newline, line ends without ;" does not produce syntax error?

What is the output of this program and how?
#include<stdio.h>
int main(){
int a=0,b=10;
a=b---
printf("the value of b=%d",b);
printf("the value of a=%d",a);
return 0;
}
In your code, writing
a=b---
printf("the value of b=%d",b);
is same as
a = b---printf("the value of b=%d",b);
which is an expression with undefined behavior, as an attempt is made to change and use the value of variable b in two subexpressions without a sequence point in between. Hence, the output of this code cannot be justified.
Without the above problem, in general, the syntax is similar to
x = (y--) - (<return value of printf() call>)
which is a perfectly valid syntax.
Note:
Why a = b---<something> is treated as a = (b--) - <something> and not a = b - -- <something> is due to the maximal munch rule.
Strictly speaking, as others have said since this is undefined behaviour, the result could be anything . And while they're right, it doesn't explain why you get this specific answer in this specific compiler.
In practice b will usually be printed as 9, or 10 depending on whether the compiler does the decrememnt first or the printf first.
printf returns the number of characters printed. Which I think is 16 or 17 in this case.
So this is like writing a = (b--) - 16; b is 10 before the decrement and it's a post decrement so this is the value used.

In C, technical explanation for how %d recognizes variables in a string

I came across an interesting output and I'd to know how the computer is working to produce this. I know that whenever you have %d in a string, you should have a variable to accompany it. When I wrote two %d's and only one variable, I expected that the computer would churn out the same value for the %d's, since it had only one variable to draw on, but for some reason, the %d's returned the value for x and the value for the variable xCubed. I want to know why the program returns xCubed without my writing xCubed at the end of the string. Here's the code:
#include <stdio.h>
int cube(int x);
int main(void){
int x = 5;
int xCubed = cube(x);
printf("Why does this number, %d, equal this number %d?", x);
return 0;
}
int cube(int x){
return x * x * x;
}
Thank you!
Your program invokes undefined behaviour. Anything could happen. Possibly the valued returned from the call to cube happens to lie next to the value of x on the stack. Of course, this behaviour being undefined means that any change to your program, or your compiler options, could result in different behaviour.
In any case, you are expected to supply two values. Do so.
printf("Why does this number, %d, equal this number %d?", x, x);
If you compiled your program with full warnings then the compiler would have warned you of your error. And you could even ask your compiler to treat warnings as errors to stop you committing the mistake.
Your program causes undefined behaviour, so anything is possible. It's some quirk of stack/register layout and calling convention for your platform that gives you the results you see.
That is because xCubed happens to be allocated just after x, which means closer to the printf part of the stack (activation frame).
printf is a vararg function, it has no implicit way of knowing how many arguments it was passed. So, when you call printf with two placeholders but just one value supplied, it will read past the first argument expecting a second and "fall" into the stack of the caller, whose nearest content is exactly xCubed.
Just to be clear: this is the reason why your code exhibits that particular behaviour, not the way it is expected to work. You have a serious bug in your code.
This was by good luck. In effect, it is undefined behaviour.
Obviously, in your case the variable xCubed was put onto stack immediately after the free space. Upon doing the printf() call, x was put immediately before that, and then the address of the format string.
If you compile this program with other optimization settings, your compiler might decide to put xCubed somwhere else, or in a register, or omit it altogether, as its value is never used.

C equivalent operator creating confusion

Program 1:
#include<stdio.h>
void main()
{
int i=55;
printf("%d %d %d %d\n",i==55,i=40,i==40,i>=10);
}
Program 2:
#include<stdio.h>
void main(){
int i = 55;
if(i == 55) {
printf("hi");
}
}
First program give output 0 40 0 1 here in the printf i == 55 and output is 0 and in the second program too i ==55 and output is hi. why
In the first example, the operators are evaluated in reverse order because they are pushed like this on the stack. The evaluation order is implementation specific and not defined by the C standard. So the squence is like this:
i=55 initial assignment
i>=10 == true 1
i==40 == false (It's 55) 0
i=40 assignment 40
i==55 == false (It's 40) 0
The second example should be obvious.
There's no guarantee about the order in which arguments to a function are evaluated. There's also no sequence point between evaluating the different arguments to the function.
That means your first call gives undefined behavior, because it both uses the existing value of i and writes a new value to i without a sequence point between the two.
In a typical case, however, each argument to a function will be evaluated as a separate expression, with no interleaving between them. In other words, the compiler will impose some order to the evaluation, even though the standard doesn't require it to do so.
In the specific case of a variadic function, the arguments are typically pushed onto the stack from right to left, so the first argument (the format string) will be at the top of the stack. This makes it easy for printf to find the format string, and then (based on that) retrieve the rest of the arguments from further down the stack.
If (as is fairly typical) the arguments are evaluated immediately prior to being pushed on the stack, this will lead to the arguments being evaluated from right to left as well.
Functions with a fixed number of arguments aren't evaluated from right to left nearly as often, so if (for example) you wrote a small wrapper taking a fixed number of arguments, that then passed those through to printf, there's a greater chance that i would have the value 55 when the first argument to printf is evaluated, so that would produce a 1 instead of a 0.
Note, however, that neither result is guaranteed, nor is any meaningful result guaranteed--since you have undefined behavior, anything is allowed to happen.
The arguments of printf are evaluated from right to left here (this is unspecified behavior, but the behaviour you noticed shows that at least the first argument is evaluated after the second). In your argument list there ist i=40, which sets the value to 40. Therefore the first printed argument is false (0).
The function printf evaluates the expressions in implementation specific manner, in this case from right to left. Hence the output:
i==55(0),i=40(Assignment),i==40(0),i>=10(1)
The reason is that the order in which the arguments to the printf function (actually any function) are evaluated, before being passed to the function, is not defined by the C standard.
The problem is not with your understanding of the == operator.
Edit: Although many authors are pointing out that printf typically evaluates its arguments from right-to-left (which I wasn't aware of), I would say it's probably a bad idea to write code that depends on this, as the language does not guarantee it, and it makes the code much less readable. Nevertheless is is a good factoid to know in case you come across it in the wild.
In the first program: The order of evaluation of the printf() arguments is implimentation defined. So this program doesn't give the same result on different implimentation of printf() So there is no guarantee about what the program will result.
It could output 0 40 0 1 as it could output 1 40 1 1 if the order of evaluation is reversed.

Resources