This is an ugly code used only to terrorize job applicants during interviews...
But I cannot understand the logic behind it.
Can someone explain why the expression with "b" is not equal to the one with "a"?
#include <stdio.h>
void main(){
int a = 1, b = 1, c = 1;
printf("%d %d %d", ++a + a++ + 1, 1 + ++b + b++, ++c + c++); // displays 6 5 5
}
Thank you very much.
Read up on Undefined behavior and sequence points.
This is a slightly different, yet similar example (thanks Zan):
2) Furthermore, the prior value shall be accessed only to determine the value to be stored.
C++ example:
std::printf("%d %d", i,++i); // invokes Undefined Behaviour because of Rule no 2
The logic is simple:
Create Undefined Behavior and let the nasal demons terrorise the job applicant. That is known as job security.
If you write to a variable, you must not access it again without intervening sequence point except to calculate the value which shall be written.
There's a second case of UB or at least Implementation Defined Behavior:
void main()
Should be one of
int main(void)
int main(int argc, char* argv[])
Just to prove that this is a terrible idea, here's the output in VS2012 (technically C++ compiler I suppose):
5 5 4
GCC & G++:
6 5 5
So apparently your interviewer tried it in GCC.
Related
#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.
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.
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.
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.
#include<stdio.h>
int main(){
int arr[ 5 ] = { 1, 2, 3, 4, 5 };
int *f = arr;
int *l = (4+arr);
while(f<l){
*f^=*l^=*f^=*l;
++f; --l;
}
printf("\n%d\t%d\t%d\n", *arr, *f, *l)
return 0;
}
My output is 1 3 3 on paper but compiler is showing 033.
Please anyone explain it to me.
Thanks in advance.
*f^=*l^=*f^=*l;
The evaluation of the operands of ^= is not sequenced, and you use the same variables several times in the same expression, with no sequence point in between.
This means that the behavior of the program is undefined. Nobody can know how that expression will be evaluated and anything can happen. The program may crash or the output can be anything.
You have to fix this bug by changing the code into this:
*f ^= *l;
*l ^= *f;
*f ^= *l;
Then each semi-colon will introduce a sequence point and there are no order of evaluation issues.
Standard references.
I actually don't care one bit how this is evaluated. If you have code and ask "what exactly does this code do", then the correct answer is "don't write that kind of code". (Except if you are writing a compiler, in which case the answer is "you shouldn't be writing compilers if you ask on stack overflow how some code should be executed").
In addition, the result is undefined behaviour in C, C++ before C++ 11, and Objective-C, so that's a good reason not to do it where it is defined. In addition, it has zero chance to pass any code review, and there is a rule "always assume that the next maintenance programmer reading your code is a violent sociopath who knows your home address".
The output is correct:
*arr = ((1^5)^1)^5);
which indeed is 0. Note that *arr is modified during the first iteration and that's all you worry about. In the second and later iterations you're not modifying *arr anymore. At that point f has been updated and doesn't point to arr anymore
A few lines explaining the maths:
1^5 = 4
4^1 = 5
5^5 = 0
EDIT:
I assumed that the language guarantees that the order of evaluation is from left to right. As pointed out by Lundin this is not the case. However, judging by the output of the executable that's most likely the way that the compiler has handled it.