2

I know that, if we declare variables inside a function without allocating memory for them, they will be lost after the function finishes its job.

The following code prints:

(null)
5
char* getString() 
{ 
  char arr[] = "SomeText";
  return arr;  
}      

int getInt()
{
    int b = 5;
    return b;
}

int main() 
{ 
  printf("%s", getString());
  printf("\n");
  printf("%d", getInt());

  return 0; 
} 

Both arr and b variables are created on the stack, so they both should be destroyed when the functions end. My question is, how come variable b doesn't get lost while variable arr is lost?

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
No N
  • 151
  • 2
  • 11
  • 1
    undefined behavior. Anything could happen. – tkausl Nov 09 '19 at 19:28
  • The difference is the `getInt()` function returns a **value** and the `getString()` function returns a **pointer** (... to a memory area that has been disposed of). Try `int *getInts() { int x[2] = {-1, 42}; return x; }` – pmg Nov 09 '19 at 19:29
  • Local variables, which includes arrays, go out of scope and end their life-time when the function ends. Pointers to such variables (and you return a pointer to an arrays first element) will become invalid as soon as the function ends. – Some programmer dude Nov 09 '19 at 19:30
  • 3
    The local variable `b` **is** lost, but its *value* is returned by the function. It would be the same situation as with `arr` if you returned a *pointer* to `b`. – Weather Vane Nov 09 '19 at 19:33
  • In C++ we solve this by returning a `std::string`. Pointers are building blocks for classes. `std::string` probably has a few pointers inside it. You don't care about that. – MSalters Nov 09 '19 at 19:38
  • 1
    As fa r as I understand, the memory used by variable b can be used by any other thing. If that happens I will also lose variable b. @pmg Why does the value doesn't get lost? – No N Nov 09 '19 at 19:38
  • 1
    Suppose passing "things" between functions is done with envelopes. When `getInt()` reaches the statement `return b;` it puts inside the envelope the value contained in the variable `b` at the time. The function `getString()` puts inside the envelope something like `0xdeadbeef` (the "decayed" `arr`). – pmg Nov 09 '19 at 19:46
  • 2
    Both functions return values. `getInt()` returns an integer value and `getString()` returns a `char*` value. Unfortunately the `char*` value returned is the address of an array that has gone out of scope and is no longer alive. – Blastfurnace Nov 09 '19 at 19:47
  • 1
    Look [here](https://ideone.com/QdoUWW). Now look [here](https://stackoverflow.com/questions/57842756/why-should-i-always-enable-compiler-warnings). – n. m. could be an AI Nov 09 '19 at 19:57

2 Answers2

4

Both getInt and getString return a value.

getInt returns an int value of 5. It remains 5 in the caller.

getString returns a char * value that points to arr. While the caller receives a pointer, the thing it points to, arr, no longer exists (in the C standard’s model of computation) when the function returns.

Thus, it is not the value being returned by the function that is the problem so much as its meaning. The number 5 retains its meaning. A pointer to a thing that ceases to exist does not retain its meaning.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
4

A unique and often confusing feature of C (and inherited by C++) is that an array when used in an expression is not treated as a collection of values, but (most of the time) as a pointer to its first element. So, when you return an array from a function, you are returning the address of its first element.

Dereferencing the address of an object with automatic storage duration that is no longer in scope results in undefined behavior.

When you return a value from a function, a copy of the value is returned to the caller.

Thus, when you return an integer, the caller receives a copy of that integer value.

If the value is a pointer, the copied value is a pointer. If the pointer is pointing to an invalid object, then if the receiver of the pointer tried to dereference the pointer value, it would result in undefined behavior.


There are 3 exceptions: (1) As an operand to &; (2) As an operand to sizeof; and (3) A string literal used to initialize an array. In C++, there are other exceptions: (4) As an operand of decltype; (5) As the function argument to a reference parameter; (6) An object to initialize a reference variable; ... probably something else I am forgetting...

jxh
  • 69,070
  • 8
  • 110
  • 193