Can a global pointer point to a local variable?

6

In the case below, for example:

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

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

    
asked by Carlos 21.11.2015 в 01:52

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();
    return 0;
}

See running on ideone .

The problem is not the variable being global. It points to a local variable. The code should only have a pointer pointing to a stack address or heap . What happens if I do not respect this?

Codes can thus point to arbitrary values for addresses that do not have guaranteed data.

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

Note that language does not guarantee this. But that's the way it usually works. The risk is yours. If you know what you're doing, it'll be all right.

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 Main() function. This variable has another value. So far so good.

Now we call teste3() . Note that we created a local variable with a new value. But we did not change 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 at him. What happens now?

We call the teste() that prints the value of the local variable of teste3() that was never referenced by the pnum pointer. Why does this occur?

Because at the end of the function teste2() its content is uncropped. It is not deleted, but is free to use. With the teste3() call, it is stacked in the same place where it had teste2() data. By coincidence the value of the local variable of teste3() was placed in the same place where the local variable of teste2() was. But it was only a coincidence. It was lucky, it could be worse.

When you go up the stack it even gives you predict which values will be in the stack, but when you get off the stack, whatever value you have there should be considered junk and should not be accessed. Language does not stop.

The two reasons for the heap to exist are: having very large data that could pop up the stack or just being able to have "live" data created by a higher function being accessed by lower address functions "guaranteed."

    
21.11.2015 / 02:20
3

Yes, because the pointer points to the memory address you can either modify the local variables through a global pointer or simply by passing the address of your local variable to a pointer as a parameter to a f(&ponteiro) function 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 declared variable in the main function:

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

See working at Ideone .

See more about pointers here in this question .

    
21.11.2015 в 02:25
2

Memory can be divided into two areas: stack and heap ). Memory allocated through malloc and deallocated with free is the memory that is in mount . The local variables are in stack .

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

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

So if we have a case where the main() function calls a() which in turn calls b() , the stack will look something 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....  +
+---------------------------------------+

Suppose that b() returns the address of your local variable 3 (4120) to a() . This way, after b() returns, the stack looks 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 in the heap, so if a() uses this address for something, it may cause segmentation to fail, corrupt memory, or read garbage in memory that b() has left behind. But regardless of the case, this is undefined behavior.

The thing is funny, if a() call c(int *) passing this address obtained from b as a parameter, and assuming that the pointer size 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 address 4120 will fall in the middle of a c() variable. In fact, worse than that, half in each of the variables. When c() tries to change the value contained in this address, it is corrupting its own variables. Needless to say, the result of this is probably catastrophic.

    
21.11.2015 в 02:32