0

As much as I know after every function call the local variables are discarded. But when I executed this piece of code the variables retain their previous value. What is this behavior?

Compiler: gcc 4.8.4

#include<stdio.h>
void t();
int main(void){
    t();
    t();
    t();
    return 0;
}

void t(){
    int i;
    i++;
    printf("%d\n",i);
}

Output:

4bh1@mybox:~/C-fi$ ./test 
1
2
3
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
4bh1
  • 182
  • 2
  • 13
  • 11
    This [behavior is undefined](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior). – user3386109 Jul 19 '16 at 19:29
  • Duplicate of http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope (although it is for a different programming language) – Pascal Cuoq Jul 19 '16 at 21:51
  • 1
    @PascalCuoq it is not a dupe of that at all. The OP is not trying to access a variable when it is out of scope. – NathanOliver Jul 20 '16 at 01:31
  • @NathanOliver I believe that when you say “out of scope” you mean “after its lifetime”. – Pascal Cuoq Jul 20 '16 at 04:54
  • @PascalCuoq Yes and that is not what the OP is doing. The OP is using an uninitialized variable. That is a different thing. – NathanOliver Jul 20 '16 at 11:47
  • It's true that the behaviour is undefined. It certainly would be correct to say that and nothing else. But it would be even better to explain why. That way others can develop the kind of rich understanding that can only be found when dig deep. – Luis Perez Jul 20 '16 at 15:34

3 Answers3

15

The behavior of your program is undefined. i is uninitialized so any use of i besides setting its values is undefined behavior.

Most likely what you are seeing is i gets the same "stack space" allocated to it each time so you are just reusing the previous value.

Do note that when an int(or any type) goes out of scope the compiler does not reset it value to something as that would be wasted cpu cycles. This is why you can see the value increasing as it is just reusing what was in the memory space.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • 5
    Remember that undefined behavior is also unpredictable behavior, so even if you have an explanation you should never assume it will work the way you expect. *Never* allow your programs to have undefined behavior! – Mark Ransom Jul 19 '16 at 19:38
  • @NathanOliver Yup I was thinking the same that the value was being reused. Is there any way to avoid that ? other than _**int i=0;**_ or its just a compiler thing – 4bh1 Jul 20 '16 at 10:59
  • 1
    @4bh1 Well you could always set the value to something before it goes out of scope but I do not think there is an automatic way to reset the variable. You really don't need to though as one should always initialize a variable if you adhere to RAII. – NathanOliver Jul 20 '16 at 11:51
  • POD type is C++ terminology, isn't it? The question is about C. – glglgl Jul 20 '16 at 13:24
  • @glglgl The question was originally tagged with C++. I guess I can remove that since it was changed to C. – NathanOliver Jul 20 '16 at 13:25
3

It's the stack man

In this particular case it probably has to do with the how memory is allocated on the for the variables in a function.

There is a continuous block of memory that is reserved for function variables called the stack.

When you call a function a portion of the stack is reserved for that function and that's where the value for the variables in that function are stored.

When you exit the function that portion in the heap is not reserved anymore and will be used by the next function that is called. BUT, the values in it are not zero'd out, the values remain there.

So in this case if you don't initialize your function variables it's going to contain whatever happen to be in the stack.

In this case since you are calling the same function over and over again what's going to be left over is going to be predictable. But in most circumstances you are going to have issues and it won't be predicable.

For example if you call a different function in between.

Breaks when calling a different function in between

#include<stdio.h>
void t();
void otherFunction();
int main(void){
    t();
    otherFunction();
    t();
    t();
    return 0;
}

void t(){
    int i;
    i++;
    printf("%d\n",i);
}

void otherFunction(){
    int x = 10;
}

Output:

1
11
12

It also wouldn't behave the same if x() were called deeper in the stack:

Breaks when called from different depth in the stack

#include<stdio.h>
void t();
void callT();
int main(void){
    t();
    callT();
    t();
    t();
    return 0;
}

void t(){
    int i;
    i++;
    printf("%d\n",i);
}

void callT(){
    t();
}

Output:

1
1
1
2

Talk about undefined behaviour, I can't even explain that.

It get's worse in our examples were using int or nothing in our functions. The stack doesn't know what kind of data is in the stack it's just a bunch of bytes. So you can end up with a situation where the data was incorrectly interpreted into another type.

For example say one of the functions used a float instead of a int.

Breaks when different types are used

#include<stdio.h>
void t();
void assignFloat();
int main(void){
    t();
    assignFloat();
    t();
    t();
    return 0;
}

void t(){
    int i;
    i++;
    printf("%d\n",i);
}

void assignFloat(){
    float x = 10;
}

Output:

1
1092616193
1092616194

This is not the behaviour you are always going to get, the behaviour is "undefined" which means that you can't predict the behaviour from compiler to compiler or even from one compiler configuration to another. Undefined means it's unreliable and you shouldn't do it.

The examples in this answer were tested using:

g++ (GCC) 5.3.1 20151207 (Red Hat 5.3.1-2)

Using the online tool:

http://www.tutorialspoint.com/compile_cpp_online.php

Luis Perez
  • 27,650
  • 10
  • 79
  • 80
0

You should initialize your variable i . You could also use void for the signature of t().

Here's an updated version (also took the liberty of using %d with printf):

#include<stdio.h>
void t(void);
int main(void){
t();
t();
t();
return 0;
}

void t(void){
int i = 0;
i++;
printf("%d \n",i);
}