1

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?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
mariappan .gameo
  • 171
  • 1
  • 1
  • 15
  • If the question comes up in an interview, you should specify that the second program exhibits undefined behaviour because the order in which the arguments are evaluated and side-effects complete is unspecified, which leads to a violation of C11 [§6.5 Expressions ¶2](http://port70.net/~nsz/c/c11/n1570.html#6.5p2) as noted in this [comment](https://stackoverflow.com/questions/56086241/why-does-int-x-5-printfd-d-d-x-5-x-10-x-5-in-c-print-0-10-0#comment98810531_56086241) to another question. – Jonathan Leffler May 11 '19 at 02:21

5 Answers5

5

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.

JohnH
  • 2,713
  • 12
  • 21
4

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).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
2

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[]) { /* ... */ }

Achal
  • 11,821
  • 2
  • 15
  • 37
2

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.)

halfer
  • 19,824
  • 17
  • 99
  • 186
melpomene
  • 84,125
  • 8
  • 85
  • 148
2

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.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103