I'll try to give an answer. But first... please notice that the C standard does not define a stack. That is an implementation detail whether a stack is used or not. That said - almost every modern implementation uses a stack for handling function calls and their local variables.
Your are correct that each function (aka each stack frame) contains its own local variables that can't be directly changed by other functions.
Lets take an example:
void foo(int x)
{
x = 5; // Change x to 5 but it does NOT change x in callee
}
int x = 42;
foo(x);
// Here x is still 42 because foo can't change the value of x in the callee
But what if we use pointers?
void foo(int* x)
{
int y = 8;
x = &y; // Change x to point to y
}
int x = 42;
foo(&x);
// Here x is still 42 because foo can't change the address of x in the callee
So the two examples above shows that foo
can't alter variables in the callee.
But... Now what can you do with a pointer?
void foo(int* x)
{
*x = 8; // Change x to be 8 (notice the * - it is the key)
}
int x = 42;
foo(&x);
// Here x is changed to 8 because foo can use the pointer to x to change its value
So yes: The called function can change the value of a variable in the callee (a variable in its stack frame). But it requires that you pass a pointer to the variable. And that is exactly what scanf
expects - a pointer to an object so that it can change the value of that oject..
In your specific case you pass a pointer to x
:
scanf("%d",&x);
^ address of x, i.e. a pointer to x
therefore scanf
can change the value of x
in the callee.
In general you can say: If you pass a pointer to a local variable to a function, you also give that function the ability to change the value of that variable
That is a very important concept within C so it's something that you need to understand fully when doing C programs.