Home > Software engineering >  C What Is Scope Of A Pointer?
C What Is Scope Of A Pointer?

Time:02-20

Here I have some c code all in 1 cpp file:

struct Object
{
    int* data;
}

Object obj;

void pizza()
{
    int joe[] = {5, 3, 4, 7, 8};
    obj.data = joe;
}

int main()
{
    pizza();
    std::cout << obj.data[2];
    return 0;
}

obj.data is just a pointer to a array of ints, and I initialize it in the pizza function, so by the time it leaves this function obj.data should be pointing to NULL becuase this data only existed in the scope of pizza.

But this is not the case, when I std::cout a value of this array the data is still there even though the pointer points to data that is no longer valid.

How does this work, is the data being copied? Is this safe or can it lead to problems?

CodePudding user response:

In this function

void pizza()
{
    int joe[] = {5, 3, 4, 7, 8};
    obj.data = joe;
}

joe only exists while that function is running, it is allocated on the stack. Once pizza finishes that memory is released automatically. But you have saved the address of joe in obj.data. That means that obj.data now points at invalid memory.

The reason it 'works' is because you were 'lucky', reading that pointer is invalid, triggering whats called 'Undefined Behavior' aka UB. In some cases (the hardest to debug) everything seems to work but later when you change something (or a customer places an unexpectedly large order) it will fail.

In your case try repeating the std::cout, it will probably give you a different answer

I will echo what Ted Lyngmo said in another answer (and add my own)

  • do not use raw pointers, use std::shared_ptr or std::unique_ptr
  • dont use raw arrays use std::vector

CodePudding user response:

C What Is Scope Of A Pointer?

A pointer has the same scope as any other variable. It's usually a local and sometimes a global variable.

{
    auto im_a_pointer = function_that_returns_a_pointer();
} // `im_a_pointer` goes out of scope and can't be used anymore

It's usually not the pointer itself that's the problem. Dangling pointers are though. Dereferencing a pointer to an object that has ended its life makes your program have undefined behavior.

void pizza()
{
    int joe[] = {5, 3, 4, 7, 8};
    obj.data = joe;
} // `joe`s life ends here - try to access it and you'll have undefined behavior

Since pointers point at objects that are (presumably) alive, passing pointers around doesn't cause problems. You can return a pointer by value. It copies the pointer and doesn't have any effect on the lifetime of the object it's actually pointing at.

On that topic - not returning raw owning pointers from any function is one way to keep sane. Use std::unique_ptr<type> if ownership is in the mix.

CodePudding user response:

The values of array joe are placed in a stack data structure at run time. This stack is torn down when it pizza() exits. As an optimization, torn down means to reset the top of stack location: the actually values in the reclaimed stack space do not need to be changed, and indeed your compiler has chosen not to reset the values in the reclaimed stack.

When the function pizza() exits, the value of obj.data is not modified, i.e. the value is retained. And seeing the values in the reclaimed stack has not been modified at the time the value is printed, it will still output the value 4. The fact that it is the value 4 is pure chance, because that memory location could have been reused. To illustrate this, the following code has a high chance of no longer printing 4, because the chances are that the method pie() will overwrite the previously reclaimed stack space.

#include <iostream>

using namespace std;

struct Object
{
    int* data;
};

struct Object obj;

void pizza()
{
    int joe[] = {5, 3, 4, 7, 8};
    obj.data = joe;
}

void pie()
{
    int bob[] = {10, 11, 12, 13, 14};
}

int main()
{
    pizza();
    pie();
    std::cout << obj.data[2];
    return 0;
}
  • Related