Scope of C array and function pointers

I have a situation like this:

{
    float foo[10];
    for (int i = 0; i < 10; i++) {
         foo[i] = 1.0f;
    }
    object.function1(foo); // stores the float pointer to a const void* member of object
}
object.function2(); // uses the stored void pointer

      

Is the content of the float pointer unknown in the second function call? It seems that I am getting weird results when I run my program. But if I declare float foo [10] const and initialize it in the declaration, I get correct results. Why is this happening?

+2


source to share


8 answers


For the first question, yes, using foo after out of scope is wrong. I'm not sure if he defined the behavior in the spec or not, but this is definitely wrong. The best random scenario is that your program will crash immediately.



As for the second question, why does this make const work? This is an implementation artifact. What is likely to happen is that data is written to the data section of the DLL and is therefore valid for the life of the program. The original sample instead pushes data onto the stack, where it has a much shorter lifespan. The code is still wrong, it just works.

+8


source


Yes, foo [] is out of scope when calling function2. It is an automatic variable stored on the stack. When the code exits the block in which it was defined, it is freed. You may have stored the link (pointer) elsewhere, but that is pointless.



+2


source


In both cases, you get undefined behavior. Everything can happen.

You keep a pointer to a locally declared array, but as soon as the scope containing the array definition leaves the array, all of its members are destroyed.

The pointer you have now saved no longer points to a float, or even a valid memory address that can be used for a float. It can be an address that is reused for something else, or it can continue to contain the original data unchanged. In any case, it is still invalid to try to dereference a pointer, either for reading or writing a float value.

+1


source


For any declaration like this:

{
   type_1 variable_name_1;
   type_2 variable_name_2;
   type_3 variable_name_3;
}

      

variables are allocated on the stack.

You can print the address of each variable: printf ("% p \ n", variable_name) and you will see that the addresses increase by a small amount approximately (but not always exactly equal), the amount of space each variable has to store its data. The memory used by the stack variables is recycled when "}" is reached, and the variables are out of scope. This is accomplished with good efficiency by simply subtracting some number from a special pointer called the "stack pointer", which says that the data for new stack variables will be allocated over their data. By increasing and decreasing the stack pointer, programs have an extremely fast way to design, since the memory for variables will live. Its such an important concept,that each main processor maintains a special piece of memory just for the stack pointer.

The memory for your array is also popped and unloaded from the program's data stack, and your array's pointer is a pointer to the program's stack memory. Although the language specification says that accessing data belonging to out-of-scope variables has undefined consequences, the result is generally easy to predict. Typically your array pointer will continue to hold its original data until new stack variables are assigned and data is assigned (i.e. the memory is reused for other purposes).

So don't do it. Copy the array.

I'm less aware of what the standard says about constant arrays (possibly the same thing - the memory is invalid when the original declaration is out of scope). However, your different behavior is understandable if your compiler has allocated a chunk of memory for constants, which is initialized when your program runs, and then foo allows you to point to that data when it comes into scope. At least if I were writing a compiler, perhaps what I would be doing as very fast and leading to the least amount of memory used. This theory can be easily tested as follows:

void f()
{
   const float foo[2] = {99, 101};
   fprintf( "-- %f\n", foo[0] );
   const_cast<foo*>(foo)[0]  = 666; 
} 

      

Call foo () twice. If the print value is changed between calls (or an invalid memory access exception is thrown), its a fair bet that the data for foo is allocated in a special area for the constants above which the code above was written.

Allocating memory in a special area does not work for non-const data, since recursive functions can lead to the simultaneous existence of many stacks on the stack, each of which can contain different data.

+1


source


This behavior is undefined in both cases. You should be aware that the stack-based variable is freed when the control leaves the block.

0


source


The memory associated with foo is out of scope and fixed. Outside {}, the pointer is invalid.

It is a good idea for objects to manage their own memory rather than referring to an external pointer. In this particular case, your object can independently allocate its own foo and copy the data into it. However, it really depends on what you are trying to achieve.

0


source


Currently, you are probably just setting the pointer (can't see the code, so I can't be sure). This pointer will point to the object foo

that is in scope at that point. But when it goes out of scope, all hell can break down, and the C standard cannot guarantee any guarantees of what happens to that data when it goes out of scope. It can be overwritten with anything. It works for an array const

because you're in luck. Do not do that.

If you want the code to work as it is, function1()

you will need to copy the data into the object. This means that you also need to know the length of the array, which means that you will need to pass it or have a good finalizer.

0


source


For simple tasks like this, a simple answer is better than 3 paragraphs on stacks and memory addresses.

There are two pairs of curly braces {}

, one inside the other. The array was declared after the first left parenthesis {so it stops before the last parenthesis}

the end

When answering the question, you must answer it at the level of the person asking, no matter how well you understand the problem yourself, or you may confuse the student.

-a successful ESL teacher

0


source







All Articles