0

Following is my code:

#include<stdio.h>

int i =5;

int main(i)
{
 if(i<10)
  printf(" %d\n",printf("%d",i+main(++i)));
 return 0;
}

Output

(in both both Ideone.com and Codeblocks)

10 2

9 1

8 1

7 1

6 1

5 1

4 1

3 1

2 1

Can someone explain the reason behind this output? I expected 91, 81, ...., 51. Also, is it true that recursive main() results in unexpected outputs?

PS: This is a program that I had found in an online forum.

dpaks
  • 375
  • 1
  • 13

3 Answers3

4

Firstly, "implict int" rule has been outlawed a long time ago. int main(i) { ... is not a valid function declaration. The code does not compile in a compliant C compiler.

Secondly, expression i+main(++i) is not sufficently sequenced. It causes undefined behavior. It is illegal to read variable i and independently modify variable i in the same expression without proper sequencing between these actions. The language does not define the behavior in this case.

In practical terms, it is not known whether the value of the first i in i+main(++i) will be read before ++i modifies the value of i or after it. The language makes no guarantees about it. You begin with i equal to 1. For that value of i it is not clear whether the first evaluation of i+main(++i) expresision will be equivalent to 1+main(2) or 2+main(2). This is what happened in your experiment. You for some reason assumed that the first i will be read before i gets incremented. In reality, it worked the other way.

P.S. Formally, C language (as opposed to C++) seems to allow manual calls to main. However, the issue you are having has nothing to do with main being recursive.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Even if i am giving int i as an argument to main(), the same result is obtained. Also, could you please elaborate your second paragraph? – dpaks Aug 30 '14 at 04:41
  • 3
    @code_dweller: The second paragraph says that it is not known whether `++i` will update the value of `i` before the first occurence of `i` is read or after it. I.e. it is not known whether the very first recursive expression will be equivalent to `5 + main(6)` or to `6 + main(6)`. The language though just says that the behavior is undefined. – AnT stands with Russia Aug 30 '14 at 04:43
  • Got it! So, left to right associativity does not apply to it right? – dpaks Aug 30 '14 at 04:45
  • 1
    @code_dweller Associativity is not the same as order of evaluation. Associativity is left to right, but order of evaluation is unspecified. – Raymond Chen Aug 30 '14 at 04:47
  • 1
    @code_dweller: Associativity and operator precedence only describe *groupings* between operators and their opeands. Associativity and operator precedence have absolutely no relation to the *order of evaluation*. Just because some operator is left-associative does not mean that its operands will be evaluated left-to-right. Not at all. – AnT stands with Russia Aug 30 '14 at 04:48
  • But, how in the world it prints a value as low as '2' even though I agree that the code results in undefined behaviour? I started with i=5 and there is no decrement operator. – dpaks Aug 30 '14 at 04:57
  • And I thought I understood C. So the compiler chose to evaluate from the right evaluating main first, resulting in 10. What I don't understand is why doesn't i + main(++i) at i = 5 then evaluate to 10 + 0 (by the time main comes back i = 10)? – Dejan Jovanović Aug 30 '14 at 04:58
  • 1
    @code_dweller: Well, I got confused myself. The global `i` (intialized with `5`) is not used anywhere at all. All calculations are performed with the *local* variable `i` declared as a parameter of `main`. It actually acts as the `argc` parameter of `main`. The environment performs the very first call to main with `i` set to `1`, indicating one implicit program argument (program name itself). So, the starting value of `i` is actually `1`. – AnT stands with Russia Aug 30 '14 at 06:13
  • @AndreyT So, implicit int is allowed?(I didn't get any warnings when I compiled). Secondly, why global i is not used? (Its scope is global and hence main() could see it right?) – dpaks Aug 30 '14 at 06:27
  • 1
    @code_dweller: Global `i` is hidden (shadowed) by local `i`. Every time you say `i` in `main`, it refers to the local `i`. Because of that it is impossible to refer to the global `i` from `main` (actually, it is possible, but it is a different story). "Implicit int" was allowed in the original ANSI C - C89/90. Apparently you are running the compiler in C89/90 mode. – AnT stands with Russia Aug 30 '14 at 06:34
0

There are a number of undefined bits of the puzzle, but printf is the key to the output. Others have detailed the illegality of the i+main(++i) expression, so let's just look at the printf to analyze the output:

printf(" %d\n",printf("%d",i+main(++i)));

There are two printf statements, where the printf("%d",i+main(++i)) must be evaluated first in order to provide output to the other. So choose your undefined value and plug that in the %d. From here on out the behavior is defined.

man printf - Returned value:

Upon successful return, these functions return the number of characters printed

Given that printf("%d",i+main(++i)) outputs 10 in the first case, the return is 2 for the two characters printed. That value of 2 is passed to printf(" %d\n",.. giving the output for the first pass as:

10 2

Choose your undefined behavior on the second pass and the value for i+main(++i) is 9. The return for printf("%d",i+main(++i)) is now 1 giving your second line of output:

 9 1

And so on and so forth... I cannot explain the undefined 10, 9, 8, ... but the rest makes sense.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
-1

The argument of main, the variable i, is assumed to be int and it takes over the global i locally. As an argument to main, the first time it is called it has the value "number of arguments"+1. So, if you run your program with no arguments, the first call to main starts with 1. Try running your program with some arguments and you will get a different result.

For me

./a.out a b c
10 2
9 1
8 1 
7 1
6 1
5 1

Understanding the order of evaluation is tricky. Consider the following program and it's output and it might become clearer what the compiler is doing (or not).

#include<stdio.h>

int f(int x) {
  printf("f with x = %d\n", x);
  return x;  
}

int g(int x) {
  printf("g with x = %d\n", x);
  return x;  
}

int main()
{
  int i;

  i = 0;
  printf("%d\n", f(++i) + i + g(++i));

  i = 0;
  printf("%d\n", (f(++i) + i) + g(++i));

  i = 0;
  printf("%d\n", f(++i) + (i + g(++i)));
}

Output

f with x = 1
g with x = 2
4
f with x = 1
g with x = 2
4
f with x = 1
g with x = 2 
5
Dejan Jovanović
  • 2,085
  • 1
  • 16
  • 22