1

Since i am new to C Language i was learning it from tutorials point when i encountered a peculiarity in functions which got my head banging while understanding it.

I have learnt that if variables are defined inside a function then there scope is local to that function and whenever the control transfers from function the variables are no more available and cleaned.

But its not in the case i have created, the program below is still printing the value of variable p which is defined in the test function so when control from test function is transferred why i am still able to get its value? its still printing the value of variable p that is 80 in screen why?

#include <stdio.h>

int *test();

int main()
{
    int *ab
    ab = test();
    printf("%d\n",*ab);
    return 0;
}

int *test()
{
    int p = 80;
    return (&p);
}


Help me understand this peculiarity Please.

Saddam
  • 1,174
  • 7
  • 14
  • 8
    Oh, welcome to C, and memory and UB – user13863346 Sep 09 '20 at 12:28
  • 1
    Does this answer your question? [Undefined, unspecified and implementation-defined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) – KamilCuk Sep 09 '20 at 12:30
  • What you have learned is still true. The fact that you cannot easily demonstrate it like you tried does not change that. It just means you have just learned how unreliably ugly and dangerous anything around the topic of "Undefined Behaviour" is. Read up on it. If you do not hate it afterwards you should read again. Only when you hate it and are afraid of it you really understood it. – Yunnosch Sep 09 '20 at 12:32
  • @KamilCuk Go ahead. Hammer it. – Yunnosch Sep 09 '20 at 12:34
  • Look for [[c] return local variable](https://stackoverflow.com/search?q=%5Bc%5D+return+local+variable), e.g. https://stackoverflow.com/q/6441218/1741542 which is almost the same. Ignore the top voted answer and start with answer https://stackoverflow.com/a/6449811/1741542 – Olaf Dietsche Sep 09 '20 at 12:35
  • Please see [What is undefined behavior and how does it work?](https://software.codidact.com/questions/277486). – Lundin Sep 09 '20 at 12:45
  • I think that "cleaned" is the bit of information that you got wrong, here. Beeing UB to access a variable out of its scope and also to use an unitialized variable, you compiler is free to generete a program that does nothing at all and "preserve" the bits in that memory location until explicitly required to modify them. – Bob__ Sep 09 '20 at 12:54
  • `if variables are defined inside a function then there scope is local to that function and whenever the control transfers from function the variables are no more available and cleaned` - not completely correct. If variable is declared as `static`, it keeps its value between function runs, although still visible only within the function. And `cleaned` part isn't correct for malloc'ed variables - failure to free malloc'ed variable results in memory leak – qrdl Sep 09 '20 at 13:06

4 Answers4

4

What you are experiencing is a symptom of undefined behavior.

A variable's address is no longer valid after its lifetime ends. When you attempt to dereference that address, you may see the value you had before, or you may see something else.

Try duplicating the printf call in main and you'll likely see a different value.

What is most likely happening is that before the first call to printf the area of memory that contained p hadn't yet been overwritten. Then when printf is actually called, the stack frame for that function is using the same memory that the stack frame for test was using and the memory previously used by p is now overwritten. So when you dereferences ab in main after calling printf you'll see whatever value that function placed there.

ryyker
  • 22,849
  • 3
  • 43
  • 87
dbush
  • 205,898
  • 23
  • 218
  • 273
1

Accessing an out-of-scope variable is Undefined Behaviour , and hence, by definition, results can vary infinitely and unpredictably, as variables change (compiler flags, OS, etc.)

Your variable does go out of scope but this only means it is no longer 'reserved'. However, unlike newer languages where this may raise compile-time errors, in C this is merely a warning, which may appear if you specifically ask the compiler to give you extra warnings.

So the code will compile.

Here, the variable goes out of scope, but, assumably, no further usage of memory occurs , and so the value at the address of test stays same . If more variables were declared/initialised/used , then likely that address would have been overwritten with another value, and you would have printed something unexpected - to be real, even this result was unexpected, hence your question !

The thing to remember is - variables in C are like chairs in a hall(which is akin to memory). The chair's position, the number of chairs is all static/fixed. What can be changed is who sits at what chair.

So, if you ask a friend to sit at a convenient chair and 5 minutes later tell him he is no longer required , whether he stays there or gets up and someone takes his place is something you cannot predict without looking and reading at an out-of-scope address is similarly undefined , since it cannot be predicted beforehand !

Other analogies may be parking spaces, ship-containers, etc.

The difference is that the address won't be overwritten / 'deleted' until something else comes up which needs to be stored (this is also how Disks manage 'deletion' which is actually nothing but un-reserving hardware locations) .

And when you think about it, it makes a lot of sense from the efficiency standpoint - you no longer have to waste time doing a useless 'overwrite with 0' or whatever and instead only write when you have a real value to store to memory !

( 1 operation instead of 2, half the work.)

user13863346
  • 327
  • 2
  • 11
0

Even though the variable shouldn't be "existing" anymore, the computer is a little bit lazy, and it won't delete the value at an address.

That is how you can manipulate the memory, if you try to see memory that doesn't belong to your program, you'll be able to see some weird values, because they stay in the memory even though they aren't used anymore.

hintauh
  • 72
  • 2
  • 9
0

Here is an example that may illustrate the UB you're looking at:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int *test();
void run_random();

int main()
{
    srand(time(NULL));

    int *ab;
    int i=0, N = 5;
    for (i=0; i<N; ++i){
        ab = test();
        run_random();
        printf("%d\n",*ab);
    }
    return 0;
}

int *test()
{
    int p = 80;
    return (&p);
}

void run_random()
{
    int i=0, N=1000;
    for (i=0; i<N; ++i){
        int rvar = rand();
    }
}

In your code, the variable from test() happens to still have the expected value on the stack memory. This is what I see when re-running the function in a loop - *ab is still equal to 80, you can see it too if you comment out the run_random() call.

But when I add the second call, the call to run_random() - I start getting ab equal to N in the run_random() i.e. 1000, as that memory location is now populated with a different variable's value (it was free to use by the OS to begin with, as soon as test() stopped executing).

In your case you may end up seeing something else, of course, perhaps even still the expected value. That is the point of UB, you don't really know what will pop-up.

atru
  • 4,699
  • 2
  • 18
  • 19