-2

Why my code is showing this kind of behavior?

#include <stdio.h>

void s1()
{
    int a;
    a++;
    printf("%d ",a);
}
void s2()
{
    int aa;
    aa++;
    printf("%d ",aa);
}

int main()
{
    int i = 0;
    for(i = 0; i < 10; i++)
    {
        s1();
    }
    for(i = 0; i < 10; i++)
    {
        s2();
    }

    return 0;

}

Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Why 'a' in second function is storing value from first function?

Anshuman
  • 758
  • 7
  • 23
  • How??Both `a` and ``aa`` are not static then how their values persist?? – Anshuman Jan 30 '21 at 14:54
  • @anshuman I was confused at first and tried running the program. Got the same output as well – Gautham M Jan 30 '21 at 15:16
  • Check this answer : https://stackoverflow.com/a/1597426/7804477 It states that "Non-static variables (local variables) are indeterminate. Reading them prior to assigning a value results in undefined behavior". What was the purpose of declaring a variable inside the method without initialising it? If you had initialised the variable, then it would have worked as expected – Gautham M Jan 30 '21 at 15:24

2 Answers2

3

When you do not initialize an object with automatic storage duration (such as variables defined inside functions), the C standard does not specify what its value is, or even that it has a fixed value, or even (depending on certain factors) that the behavior of the program is defined.

In your case, it is likely the memory that was assigned for a initially contained zero, and the compiler generated code that used this uninitialized memory. After s1 completed, the program used the same memory for aa, the same way that, if you go the dentist and hang your coat on a hook and later take it and leave, a patient who comes after you may hang their own coat on the same hook. Then, in s2, aa contained the value left over from s1.

In “real world” programs, you are unlikely to see this exact behavior, for several reasons. For one, things will have happened in the program before s1 is called, so the memory used for a is not likely to contain zero. For another, the program will be compiled with optimization, and the compiler will likely use a register for a or aa rather than memory on the stack. Further, with optimization turned on, the compiler may recognize that the behavior is not defined or not fully specified and optimize it to even stranger code. And, finally, professionals compile with many warning options enabled and set to be errors rather than mere warnings, so the compiler reports errors like this before the program is deployed.

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

Congratulations, you've stumbled into Undefined Behavior. Not the first one either.

When you declare a variable with no initialization. The C standard defines it as Indeterminate Values.

3.19.2

1 indeterminate value

either an unspecified value or a trap representation

Any time you try to use an indeterminate value, you invoke undefined behavior. Anything can happen! It may take another variable's value, it may short out the sun, anything!

The Undefined Behavior section of the C standard lists this as one possible UB-

The value of an object with automatic storage duration is used while it is indeterminate.

When you do a++ (or aa++), you're incrementing the current value of a, the value being indeterminate. And thus, the language has no guarantees on the behavior. Just because it shows one behavior in one machine, doesn't mean it'll show the same behavior in all machines.

Chase
  • 5,315
  • 2
  • 15
  • 41
  • 1
    Re “Any time you try to access an indeterminate value, you invoke undefined behavior”: This is not correct. By itself, reading an indeterminate value merely gives you some value. There are situations in which reading an uninitialized object has undefined behavior, but they have further criteria. Also note: The C standard uses “access” to mean reading or writing, so accessing an object with indeterminate value is of course not a problem when you are writing it. – Eric Postpischil Jan 30 '21 at 15:02
  • @EricPostpischil My bad on using the `access` terminology, you're absolutely correct. Could you elaborate on how "using an indeterminate value" may or may not invoke UB? (assuming the indeterminate value is extracted from an object with automatic storage duration) – Chase Jan 30 '21 at 15:06
  • 1
    Reading an indeterminate value can have undefined behavior in two ways. One is it produces a trap value. Of course, that does not happen if the type has no trap values, so it does not happen for most types in most modern C implementations. The other is if C 2018 6.3.2.1 2 applies: “If the lvalue designates an object of automatic storage duration that could have been declared with the `register` storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.” – Eric Postpischil Jan 30 '21 at 15:11
  • @EricPostpischil Very interesting, I see what you mean now. Thanks so much for explaining! – Chase Jan 30 '21 at 15:12
  • 1
    So, for example, given `unsigned char x[1];`, reading `x[0]` always produces a value and never has undefined behavior, because an array cannot be declared `register`, and using `x[0]` takes the address of the element (because the array `x` is automatically converted to a pointer to its first element). – Eric Postpischil Jan 30 '21 at 15:12