-1

I understand how to use scanf(), but I'm having difficulty understanding how scanf() gains access to other functions and their stack frames. I know scanf() must be provided with an address to write data to, but I thought each function had its own private data located in its own stack frame. For example, take the simple program segment

#include <stdio.h>
int main() {
 int x;
 x = 2;
 scanf("%d",&x);
 printf("%d",x);
}

In this program, main has its own stack frame where local variable x is initialized to 2. My understanding is that scanf() also has its own stack frame. I know scanf() is given the address of x, but how is scanf() allowed to change data in main's stack frame?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278

3 Answers3

3

In this program, main has its own stack frame where local variable x is initialized to 2.

Correct.

My understanding is that scanf() also has its own stack frame.

Correct.

Scanf() is given the address of x, but how is scanf() allowed to change data in main's stack frame?

Allowed by who or what? There's nothing to prevent it from doing so. It has the address. It's in the same process. It can simply write to that address.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
2

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.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • "But it requires that you pass a pointer to the variable." --> Usually. With `char s[9]; scanf("%8s", s);` In this case, the value of array `s` is affected by `scanf()`, even though the address of the array variable `s` was not given to `scanf()` for the usual conversion of an array to the address of its first element. – chux - Reinstate Monica Jul 31 '18 at 19:58
  • @chux Isn't that just the usual decay thing? – Support Ukraine Jul 31 '18 at 19:59
  • Yes. Yet from the caller's point-of-view, `scanf("%8s", s)` looks like it is changing the object `s` and appears contrary to "requires that you pass a pointer to the variable". – chux - Reinstate Monica Jul 31 '18 at 20:03
  • @chux well yes... you are correct that it can seem confusing but that's just C. Maybe I should address that "special" C feature. Hmm... – Support Ukraine Jul 31 '18 at 20:06
1

You're on the right track. Based on how you phrased your question, I think your understanding would be improved with some additional context on 1) how pointers work, and 2) how process memory is separated.

I won't go into excessive detail, but hopefully this will clear things up for you.

The variable x in your main function is stored in memory at some address. Then, you pass that address into scanf with &x. scanf is allowed to make changes to that value at that address.

It's possible you may also be wondering why this is allowed. Shouldn't memory be protected so that not anything can change it? This is true as well. However, in the example you provided, main and scanf are being called by the same process. Among processes, yes, there will be more protection around what memory can be touched. As you continue to work with C, you'll run into segmentation faults, which is when the program crashes because a disallowed memory access occurs.

In your example above, you have one process running and so any lines of code that execute within that process will have access to that process's memory.

This resource on pointers may help: https://users.cs.cf.ac.uk/Dave.Marshall/C/node10.html.

Joshua W.
  • 11
  • 2