lbrndnr
lbrndnr

Reputation: 3389

Broken C pointer in Objective-C Header

I have a CGFloat pointer in my header that is used to point at a CGFloat array. I declare it like that: CGFloat* pointer;. In the initialization I try to set the pointer using this code:

CGFloat newArray[2] = {
            0.0f, 1.0f,
        };

        pointer = newArray;

This "actually" works. I don't get any compiler errors and stuff. When i print the second value of the array right after setting the pointer with this code: printf("%f", pointer[1]); I get the right result (1.000000). However, when I print the second value of the array in the method called next i get 0.000000 which means that the pointer doesn't point at the array anymore.

I've got two questions. How do I fix this problem and why does the pointer work right after setting it but "forgets" its value again?

Upvotes: 0

Views: 241

Answers (4)

bbum
bbum

Reputation: 162722

CGFloat newArray[2] = {
        0.0f, 1.0f,
    };

Array indices start at 0. pointer[1] prints the second element in the array, not the first. pointer[2] is off the end of the array.

CGFloat newArray[2] = {0,0};
newArray[0]; // this is the 1st item
newArray[1]; // this is the 2nd item
newArray[2]; // this is nonsense.

Note that if you try to pass newArray somewhere with the intention of using it later, it'll be badness. newArray is on the stack and will be destroyed when the scope is destroyed.

If you want a function that returns an array of two floats, you'd do:

 CGFloat *two_of_these() {
     CGFloat *newArray = malloc(2 * sizeof(CGFLoat));
     newArray[0] = 42.0;
     newArray[1] = 59.4;
     return newArray;
 }

Just make sure and call free on that return value later. Note that it is exceedingly rare to allocate something so small. Typically, it'll be a structure that is returned directly. See CGPoint, CGRect, NSRange, etc....

Upvotes: 1

Thomson Comer
Thomson Comer

Reputation: 3919

Larcus, newArray is being initialized on the stack in a non-global scope. The memory for your array is allocated in the one particular scope. When you call another method then CGFloat* pointer is no longer pointing to newArray because newArray may or may not exist at this point. If the second method isn't being called from within the first scope then strictly newArray will have been deallocated from its original stack frame. Instead, assign pointer like this pointer = new CGFloat[2]; pointer[0] = 0.0; pointer[1] = 1.0;

I think this is the only way to guarantee that the memory you are allocating will be allocated on the heap and not randomly overwritten or un-scoped.

See Wikipedia on Dangling Pointers

The punchline is that if you do not allocate memory using either malloc or new and assign that memory to a pointer, the state of that memory will be undefined. Only malloc and new can initialize memory in a way that will persist permanently across all scopes of your application.

Upvotes: 1

pabdulin
pabdulin

Reputation: 35235

In general seems like lifetime of the newArray is shorter then the pointer, so the pointer becomes invalid on a second call. To solve this, you need to move initialisation var, so it will have same lifetime as pointer. The other solution would be memory allocation at runtime (using malloc etc.), and free it after usage.

Upvotes: 0

Lou Zell
Lou Zell

Reputation: 5597

I think you get array indices from bbum's answer. 'pointer' points to an address. You set it to the address of newArray, but newArray isn't guaranteed to be around when your second method is called.

Upvotes: 0

Related Questions