-2

Suppose I have a main function as below:

void main()
{ int *p;
  p = foo(31);
  printf(“%d”, (*p)+2);
  bar(7); /* Body of function bar() not shown */ 
  printf(“%d”, (*p)+4);
}

int *foo(int x) 
{ 
  return &x;
}

Assuming the function bar() that compiles correctly, why the second result of the printf is 11 if the body of bar() does not write to its incoming arguments space.

More specifically, my question is why the incoming argument value of bar() which is 7 replaces the value 31?

What's more, when the main function pass the value 31 into foo(), how does the value 31 passed? By register? or the compiler creates a temporary variable to pass 31? And why the incoming argument of foo() and bar() share the same position in the memory

ygyao
  • 25
  • 2
  • 2
    Okay! Two words `Undefined Behaviour` – Sniper May 17 '17 at 19:32
  • 2
    @Sniper One word: Dyscalculia – EOF May 17 '17 at 19:33
  • @EOF: Why? It is UB, Sniper is right. – too honest for this site May 17 '17 at 19:35
  • @Olaf You missed all of the fun. – Eugene Sh. May 17 '17 at 19:36
  • @EugeneSh.: You're not the first to tell me. That's what I have to live with. – too honest for this site May 17 '17 at 19:37
  • @Olaf You had to be there... – EOF May 17 '17 at 19:38
  • 2
    The proper declarations for `main` are `int main (void)` and `int main (int argc, char **argv)` (which you will see written with the equivalent `char *argv[]`). **note:** `main` is a function of `type int` and it returns a value. See [**See What should main() return in C and C++?**](http://stackoverflow.com/questions/204476/) – David C. Rankin May 17 '17 at 19:41
  • Compile your code with `-Wall` and `-Wextra`, and run it with valgrind – Erik W May 17 '17 at 20:28
  • You're calling `foo` and `bar` with no visible declaration. For C99 and later, that's a constraint violation. For C90, it's undefined behavior, because the compiler will assume `foo` returns an `int` when in fact it returns an `int*`. Make sure your compiler at least warns you about this problem. To fix it, you can move the definitions of `foo` and `bar` above that of `main`, or you can add separate declarations. (Of course your program will still be buggy after those fixes.) – Keith Thompson May 17 '17 at 20:56

2 Answers2

5

Function parameters are its local variables. So in this function definition

int *foo(int x) 
{ 
  return &x;
}

there is returned a pointer to a local variable.

As result the program has undefined behavior.

You can imagine the function definition and its call the following way

p = foo(31);

int *foo( /* int x */ ) 
{ 
  int x = 31;
  return &x;
}

The variable x will not be alive after exiting the function. Thus the pointer has an invalid value that is a value that does not point to an actual object. The memory allocated for the parameter of the function foo can be overwritten by a call of other function as for example by a call of the function printf..

Take into account that according to the C Standard the function main without parameters shall be declared like

int main( void )

and function foo should be declared before its usage. Otherwise the compiler can issue a message that either there is used incompatible types or it can not find the corresponding function.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thank you for your response. Actually, I should write more precisely about my question. I don't understand why the incoming argument of bar() replace the previous value of foo(). – ygyao May 17 '17 at 20:45
  • @ygyao Because the function bar or the function printf reuses the memory early used by the function foo. So at the address where early there was the parameter x of the function foo now there can be anything that the function bar of the function printf can place there. – Vlad from Moscow May 17 '17 at 20:48
  • It seems not to be a coincident replacement. Why the incoming argument in bar(7) can replace exactly the memory address where the argument 31 stored? – ygyao May 17 '17 at 23:44
  • With undefined behaviour, anything can happen. Things can even seem to make sense, and/or be consistent. Or not — anything is OK. – Jonathan Leffler May 18 '17 at 04:55
1

The function foo receives a copy of the input parameter value in its local variable x. What foo sees does not depend on whether the argument to the function is constant or not.

The vatiable x is located on the stack and is freed when foo returns. So foo returns an address to a location in the stack. Returning a pointer to a local variable is an invitation for all kinds of problems.

In this case that same location most probably gets reused when bar is called.

Sami Sallinen
  • 3,203
  • 12
  • 16