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.