Can a global pointer point to a local variable?

Asked

Viewed 972 times

7

In the case below, for example:

int *pnum;
void main(){
  int num = 10;
  pnum = #
}

What would happen if I tried to access the pointer point value outside the main function ?

  • The program would have anomalous behavior because you are pointing to a stack frame, created when you enter the function and discarded when you leave the function, so you are pointing to "no man’s land". There are nut solutions for this e.g. make the variable Static, then it will continue to exist after the function comes out, but this could hardly be considered good practice.

3 answers

5


Let’s put a real code to see what happens:

#include <stdio.h>
int *pnum;
void teste() {
    printf("%d\n", *pnum);
}
void teste2() {
    int num = 20;
    pnum = &num;
}
void teste3() {
    int num = 30;
    num++;
}
int main() {
    int num = 10;
    pnum = &num;
    teste();
    teste2();
    teste3();
    teste();
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

The problem is not the variable being global. It is pointing to a local variable. The code should only have a pointer pointing to a local address (stack) or in the heap. What happens if you don’t respect this?

Codes like this can point to arbitrary values, to addresses that have no guaranteed data.

When we call the function teste(), it performs normally and takes the correct value, after all the pointer address is an area of the stack that is preserved. The stack frame of function Main() does not disappear when calling another function. On the contrary, one is stacked in the other.

Note that language does not guarantee this. But this is how it usually works. The risk is yours. If you know what you are doing, everything will be fine.

Then we call teste2() which changes the value of the pointer. Now it points to the local variable of this function and no longer to the function Main(). This variable has another value. So far so good.

Now we call teste3(). Note that we have created a local variable with a new value. But we have not changed the pointer to point to this variable. It will continue pointing to the local variable of teste2(), right?

But how is this possible if that variable no longer exists? Well, the memory address is still there, it’s pointing to it. What happens now?

We call the teste() which prints the value of the local variable of teste3() that has never been referenced by the pointer pnum. Why does this happen?

Because at the end of the job teste2() its contents are unspopped. It is not deleted, but is free to use. With the call from teste3(), is stacked in the same place where it had the dice from teste2(). By coincidence the value of the local variable of teste3() was placed in the same place where the local variable of teste2(). But it was just a coincidence. It was lucky, it could be worse.

When you go up the stack you can even predict what values will be in the stack, but when you go down the stack, any value you have there should be considered garbage and should not be accessed. Language does not prevent.

The two reasons for the existence of heap are: have very large data that could burst the stack or just be able to have "live" data created by a higher function being accessed by lower functions in "guaranteed" address".

4

Yes, as the pointer points to the memory address it is possible to modify the local variables via a global pointer or simply passing the address of its local variable to a pointer as a parameter for a function f(&ponteiro) or to a global pointer int * pGlobal;, see an example below:

#include <stdio.h>

int * pGlobal;

void foo(void)
{
    *pGlobal = 100;
}

int main(void)
{
    int num = 15;

    pGlobal = &num;

    printf("\n%d", *pGlobal);
    printf("\n%d", num);

    *pGlobal = 5;

    printf("\n%d", *pGlobal);
    printf("\n%d", num);

    foo();

    printf("\n%d", *pGlobal);
    printf("\n%d", num);

    return 0;
}

Accessing and modifying the variable declared in the main function:

void foo(void)
{
    *pGlobal = 100;
}

See working on Ideone.

See more about pointers here question.

3

Memory can be divided into two areas: pile (stack) and mound (heap). Memory allocated through malloc and out of focus with free is the memory that is in mound. Already the local variables are in pile.

The exact implementation of the stack depends on details such as the compiler used, the operating system, the processor instruction set and details of your machine architecture.

However, despite the differences, the cell structure in memory has similar structures. It is called pile because the function calls (stack frame) are stacked on top of each other in this memory region. Within each function call, local variables are also stacked and also a thing called a return address, which is the position at which the function execution should proceed when the function invoked then terminates.

This way if we have a case where the function main() flame a() which in turn calls b(), the battery will be more or less like the one below. Note that the beginning of the stack is at address 4072 and that each variable occupies a portion of the stack memory, each with its size:

+---------------------------------------+
+ 4072-4075: variável local 1 do main() +
+ 4076-4079: variável local 2 do main() + <--- Stack frame do main()
+ 4080-4087: endereço de retorno        +
+---------------------------------------+
+ 4088-4089: variável local 1 de a()    +
+ 4090-4093: variável local 2 de a()    +
+ 4094-4095: variável local 3 de a()    + <--- Stack frame do a()
+ 4096-4099: variável local 4 de a()    +
+ 4100-4107: endereço de retorno        +
+---------------------------------------+
+ 4108-4109: variável local 1 de b()    +
+ 4110-4119: variável local 2 de b()    + <--- Stack frame do b()
+ 4120-4127: variável local 3 de b()    +
+ 4128-4135: variável local 4 de b()    +
+---------------------------------------+
+ 4128-9999: Espaço livre na pilha....  +
+---------------------------------------+

Let’s assume that b() return the address of your local variable 3 (4120) to a(). In this way, after b() return, the stack is like this:

+---------------------------------------+
+ 4072-4075: variável local 1 do main() +
+ 4076-4079: variável local 2 do main() + <--- Stack frame do main()
+ 4080-4087: endereço de retorno        +
+---------------------------------------+
+ 4088-4089: variável local 1 de a()    +
+ 4090-4093: variável local 2 de a()    + <--- Stack frame do a()
+ 4094-4095: variável local 3 de a()    +
+ 4096-4099: variável local 4 de a()    +
+---------------------------------------+
+ 4100-9999: Espaço livre na pilha....  +
+---------------------------------------+

At this point, the address that b() returned (4110) is an unused address on the stack, and therefore if a() use this address for something, may cause a segmentation failure, corrupt memory, or read junk in memory that b() left behind. But regardless of the case, This is undefined behavior.

It gets funny if a() call for c(int *) passing this address obtained from b as a parameter, and assuming the size of the pointer is 8 bytes:

+---------------------------------------+
+ 4072-4075: variável local 1 do main() +
+ 4076-4079: variável local 2 do main() + <--- Stack frame do main()
+ 4080-4087: endereço de retorno        +
+---------------------------------------+
+ 4088-4089: variável local 1 de a()    +
+ 4090-4093: variável local 2 de a()    +
+ 4094-4095: variável local 3 de a()    + <--- Stack frame do a()
+ 4096-4099: variável local 4 de a()    +
+ 4100-4107: endereço de retorno        +
+---------------------------------------+
+ 4108-4115: parâmetro 1 de c()         +
+ 4116-4123: variável local 1 de c()    + <--- Stack frame do c()
+ 4124-4169: variável local 2 de c()    +
+---------------------------------------+
+ 4170-9999: Espaço livre na pilha....  +
+---------------------------------------+

Note that in this case the address 4120 will fall in the middle of a variable of c(). In fact, worse than that, half in each of the variables. When c() try to change the value contained in this address, you are corrupting your own variables. Needless to say, the result of this is probably catastrophic.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.