Malloc() creates space for single struct, not array of structs - iphone

I've been banging my head against this problem all day, I would be very grateful to anyone who could help out.
Here's the deal - I'm trying to create a dynamic C array using malloc(). This array will hold CGPoint structs, which I start building and assigning right after the array is built. Here's the code:
CGPoint* tempVertices = malloc(sizeof(CGPoint) * 4); //defining a collision frame
tempVertices[0] = CGPointMake(37, 46);
tempVertices[1] = CGPointMake(69, 40);
tempVertices[2] = CGPointMake(48, 6);
tempVertices[3] = CGPointMake(17, 10);
//Then I pass the pointer to my array off to a setter...
[self setVertices: tempVertices];
However, when tempVertices gets created, it seems that I'm only getting space for one CGPoint:
int test1 = sizeof(CGPoint); // 8
int test2 = sizeof(tempVertices); // 4
int test3 = sizeof(*tempVertices); // 8
When stepping through with the XCode debugger, it shows that tempVertices is a pointer to a CGPoint. When I set tempVertices[0], the CGPoint that tempVertices points to recieves that value, which is reflected in the debugger. Where did my other 3 slots go? tempVertices seems to be pointing to a singe CGPoint instead of an array. I want the array.
Any ideas on what I'm doing wrong? I know that there are other ways to fix this using C++ or other objects, but I want to stick to C if possible.
Thanks in advance!
Update :
To answer zpasternack, setVertices: is a custom written setter. And I don't know how / if it knows how big the incoming array is. I'm trying to understand straight C stuff better, so insights/explanations regarding the proper way of passing a dynamic C-array as an argument are highly appreciated. Here's what the setter looks like :
- (void) setVertices:(CGPoint*) val {
_vertices = val; //_vertices is a member variable of the type CGPoint*
//...calculate a centroid, other stuff...
}
If needed, I could wrap my CGPoints in NSValue objects and use an NSArray instead, but I sure would like to know the right way of doing it in plain ol' C.
Thanks to everyone who has commented - you guys are great :)

On your 32 bit machine, you're getting exactly what you expect. sizeof(tempVertices) is the size of the pointer, while sizeof(*tempVerices) gives you the size of a CGPint (probably two ints). You can't get the size of an allocated array with sizeof(). The value is only known at run-rime, and sizeof() is a compile time operator.

OK, after your edit I think I see what's going on. That code, exactly as you've written, should work OK. Xcode won't show you the values of any of those CGPoints, because it doesn't know it's an array, just a pointer to a single CGPoint. But it's there. Set a breakpoint right after you call setVertices:. At the gdb prompt, print some of those values.
(gdb) print _vertices[1]
$2 = {
x = 69,
y = 40
}
(gdb) print _vertices[3]
$3 = {
x = 17,
y = 10
}
Correct, see?
That's not to say there aren't issues here. For one thing, setVertices: is leaking that memory. You're allocating memory for tempVertices, holding onto that pointer, but not freeing it anywhere. The next time you call setVertices:, you'll have a leak.
A bigger issue is that nobody knows how many CGPoints are in that array, except the code that allocated the memory for it. Will it always be 4 CGPoints? What happens if somebody accesses _vertices[5] or _vertices[27]? Bad things, if you didn't allocate that much space for them.
Is there a requirement that this be a plain C array? Like, these points are going to get passed to OpenGL or cocos2d or something? If not, you might consider using some kind of array class for it. Because these aren't NSObject-derived objects you're storing, you can't use an NSArray. You could use a std::vector, if you don't mind dragging in a buncha C++. I probably would not do that.
If you're set on sticking with a C array, you should probably do some work to try to make the interface less error prone. Like I mentioned before, you'll need to track the size of the array. Perhaps you could add a parameter to setVertices: representing the number of CGPoints that the array holds. Then other parts of the code that access _vertices could check that to make sure they're not walking off the end of the array. And, like I mentioned before, make sure you free that memory before you reassign the pointer.
Messing about with pointers is fraught with danger. Tread carefully, there be dragons there.

The malloc is allocating enough space for 4 GCPoint structs and returning a pointer to the allocated space.
The first is at tempVertices + 0. It's tempVertices[0].
The second is at tempVertices + 1. It's tempVertices[1].
The third is at tempVertices + 2. It's tempVertices[2].
The fourth is at tempVertices + 3. It's tempVertices[3].

I would not use sizeof() to determine the size of an array allocated at runtime.
Have you actually had trouble assigning new CGPoint objects into your array? Does CGPointMake() perform any allocation of its own?

Related

How can I assign a Swift struct by reference?

As we know, in Swift, classes are reference objects whereas structs other data-types are value types. I'm trying to get the reference of a CGRect into a variable so I can change its value with a shorter name. Is there a way to achieve this? Attempting with an Objective-C or C++ pointer syntax is of no use here :(
let reference = someView.frame
frame = ...
If I stay at the view level it's ok because it's a reference type, but I want to include the frame in the reference.
You probably don't really want to work with references... I could be wrong, and you might have a good reason for wanting a reference. But looking at what you are trying to do, this might be a better approach:
Assign the frame that you want to work with to a variable:
var workingFrame = someView.frame
Work with the copy, making any changes that you want to make:
workingFrame = someNewRect
Update someView.frame to the new value:
someView.frame = workingFrame
There is, technically, a way to deal directly with pointers to memory addresses, but unless you have an amazingly good reason for going there, I think that most people would recommend that you avoid it.
[Edit:]
If you really want to try to work with pointers to memory addresses, then you may want to look at UnsafePointer<T>, UnsafeMutablePointer<T>, unsafeBitCast: and unsafeAddressOf:. Those types and functions will give you pointers to a struct.
For example, you can get a mutable pointer to an Int value like this:
let x = 5
let ptr: UnsafeMutablePointer<Int> = UnsafeMutablePointer(unsafeAddressOf(x))
Working with values, pointers, and memory addresses this way is discouraged, but yes, it is possible.
However, using unsafeAddressOf converts the Int to a class, so even that isn't really a pointer to the original struct. You may end up needing to initialize an UnsafeMutablePointer, allocate memory for it, and then assign a value to that memory. Then you can perform operations on the data at that memory address. Check out the documentation for UnsafeMutablePointer here.
And if you can give any more detail as to what, precisely, you are trying to do, there may be a more elegant solution. Swift does not make it easy to work with pointers, but it often provides other tools that allow you to accomplish what you need in a different way.
Here's the solution:
func pointerTo<T>(inout object: T) -> UnsafeMutablePointer<T> {
return withUnsafeMutablePointer(&object) {UnsafeMutablePointer<T>($0)}
}

Iterating through a pointer to a vector of pointers

I am trying to write an iPhone game using cocos2d and Box2D, which means I have to mix between Objective-C and C++. I have a question regarding using pointers to objects of gameLevels and levelObjects that I have created.
I have a class called GameLevel which contains a vector of levelObjects. I thought that using pointers was the way to do it, to make sure I use as little memory as possible. That means that my vector is
std::vector<LevelObject*>* levelObjects;
The LevelObject class contains the sprite, b2bodyDef and so on, all pointers as well.
The problems started when I wanted to iterate through this vector when I wanted to draw a level. The code I wrote was this:
-(void)startLevel:(b2World*) world withLevel:(GameLevel*) level{
std::vector<LevelObject*>::iterator it;
for (it = level->getLevelObjects()->begin() ; it != level->getLevelObjects()->end(); ++it) {
CCSprite* sprite = it->sprite; //Here XCode complaints about "Member reference base type 'LevelObject *' is not a structure or union" and "Use of undeclared identifier 'sprite'". I cannot seem to access any of the objects variables/methods from it->
So the question I ask is: Is this a good way to to this, with a pointer to vector of pointers? And why doesn't the iteration work?
Thanks :)
EDIT: getLevelObjects() are:
std::vector<LevelObject*>* getLevelObjects(){return levelObjects;}
Your iterators point to pointers, so you need two dereferences:
(*it)->sprite
the dereference of the iterator,
*it
gives you a LevelObject*.
You have two levels of indirection, the iterator and the pointer inside the vector.
You need (*it) to get to the pointer, and then use -> to dereference that:
CCSprite* sprite = (*it)->sprite;

iPhone - Changing an array while it's enumerated

I have a mutable array that contains the sounds that are being played.
I have a continous process that parse that array to adjust volumes and some other things.
Sometimes, a new sound is played and must be added to that array just before it's play starts.
And sometimes, I have a crash because my array "was mutated while being enumerated".
How may I solve that ?
You can't easily change an array while it's enumerating.
Enumerate through the array and note the new sound to be added (using a variable, or a separate array if you need to note more than one). When the enumeration is finished, add the sound to the array.
Alternatively, make a copy of the array, enumerate the copy and add the sound to the original one when you need to.
It would be nice to see any code here. But according what you are saying, i think the problem lies in the way that you use to iterate through the array. I guess it looks like this:
for ( type *object in myArray) {
...
}
Now, as you exception tells you, you can't modify the array while doing this. If you, on the other hand, access the array's values via the indexes, it should work:
for (int i = 0; i < myArray.count; i++) {
[myArray objectAtIndex:i]...
}
Keep in mind however, that the indexes aren't 'stable' that way, especially if you remove objects.

Objective C, Memory Management

1) What is the reason for the use of retain?
For example, in a setter method:
- (void) setCount: (int) input {
[intCount autorelease];
intCount = [input retain];
}
2) the autorelease-Method: Is it deleting an old object or preparing the new one?
3) Why the retain-method is called at the input-object?
Would
intCount = input;
be wrong?
And why?
Retain is used to increment the retainCount of an object. NSObjects have a property called retainCount which maintains a count on the number of references that are currently held on an object. When the retainCount of an object reaches 0, the object can be released from memory. Effectively this prevents an object from being released from memory if it's still in use elsewhere.
The autorelease method does not delete an old object and does not prepare the new object. It is effectively a pre-emptive call to release the object (autorelease is much more complicated than that and you should read up on it in the Memory Management Guide.)
In your case intCount = input wouldn't be wrong because you're working with a primative. However if input were an object then you'd need to be calling retain on it. In fact you don't even need to be writing your own getters/setters for primatives (or objects), but instead should be using Declared Properties. In fact you're almost always better off using Declared Properties and if you do want to roll your own, get to know the pitfalls of doing so first.
I recommend you read this. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
The answers to your questions have been answered fairly well so let me just add that if you can use garbage collection you should. It makes everything so much easier. It isn't a panacea and you still should learn to use the retain/release mechanism but unless you are dealing in some high volume memory calls, creating and deleting lots of objects, then just use garbage collection.
It can be found under Project | Edit Project Settings | Build
Then just search for "garbage" and you'll see it.
If you are doing iOS development and cannot use garbage collection I apologize for giving unhelpful information but it still stands for non-iOS development.
To answer ur question specifically:
1). the use of retain is to declare the ownership of an object. In this case, intCount retains the ownership of input, in case the input got released somewhere else, u can still use the intCount.
2). the autorelease of intCount is to relinquish the ownership of the old value. That avoid the memory leak of the old value. If u don't release the old value, and u assign a new value to this pointer, the old object will always be there and never got released, which will cause the memory leak.
3). if u don't retain the input, and the parameter of input got released somewhere else. then if nowhere else retain this object, it will get freed. So u can't use intCount as well. That's why u need to retain it or copy it.
But i think if u do intCount = input; it should be fine. Because int is not an object, it's just a type. So I think the whole method is okay to be written like this:
- (void) setCount: (int) input {
intCount = input;
}
But if its a pointer, u should not assign the new value to the old one directly.

Why does Instruments say this code is leaking?

I have this snippet of code from a class created by Erica Sadun, that Instruments says is leaking:
- (void)cacheBeginPointForTouches:(NSSet *)touches
{
if ([touches count] > 0) {
for (UITouch *touch in touches) {
CGPoint *point = (CGPoint *)CFDictionaryGetValue(touchBeginPoints, touch);
if (point == NULL) {
point = (CGPoint *)malloc(sizeof(CGPoint));
CFDictionarySetValue(touchBeginPoints, touch, point);
}
*point = [touch locationInView:self.superview];
}
}
}
Instruments is pointing to
point = (CGPoint *)malloc(sizeof(CGPoint));
as the leaking line.
As this malloc stuff is not familiar to me. I know that it allocates memory, but as I never worked with C, C++ and other flavors of C, malloc and I are not acquaintances.
Another question I don't understand is why she put an asterisk before "point" on
*point = [touch locationInView:self.superview];
So, do you see something wrong with the code and why instruments are saying it is leaking there? An explanation about the asterisk is a bonus! :)
thanks.
The rules for malloc are quite simple. Once you're done with the memory, you should free it, using free(pointer). So at some point in your code, the dictionary will be used to get the CGPoints. If your program does nothing after this with the CGPoints (and the pointer is removed from the dictionary), you should call free(point) on them.
The line
*point = ...;
means to say: put ... in the location in memory, pointed to by point. The dictionary contains these pointers to your CGPoint values, and as you see you can easily first store the pointer, and only then fill the memory pointed to (although, I must admit, this is not very intuitive)
The code snippet is leaking, because it is not complete. What it does is to allocate memory for a CGPoint object. This has to be free'd when it is no longer in use. You have omitted that part.
In this case, the CGPoint object seems to be used in the CFDictionary. So there should be code to determine when it is safe to free it again.
At a guess, you have probably not created the dictionary properly. A regular dictionary thinks you'll be using the CFRetain/CFRelease pattern to hold on to objects - however, you can attach alternate handlers that use your own memory mamagement scheme.
You should check the CFDictionaryNew() call in your code and make sure it matches the one in Erica's. I suspect she has a custom value for valueCallbacks while you probably don't.
Without knowing the context, I'm guessing the compiler doesn't like that the there is no check to see whether or not malloc fails (malloc = memory allocation, it grabs available memory and assigns it to your program variable). Also, this snippet by itself does not free the malloc'd memory (although I'm assuming this is done elsewhere).
Also, the "*" dereferences the value. For example, in standard C, if I write:
int val = 1;
int *p = &val;
printf("%d\n",*p);
*p = 2;
printf("%d\n",*p);
I'd get:
1
2
The * allows you to reference the object to which the pointer is pointing. In the example above, "p" is a pointer, but "*p" is the actual value the pointer is referencing ("val").
malloc() and free() are like [NSObject alloc] and [NSObject release] in Objective-C. malloc() allocates memory and returns a pointer. free() tells the OS that the memory is no longer needed. A malloc() without a free() is then, by definition, a memory leak.
It's not clear here whether there is an actual memory leak, since the pointer is being stored in a dictionary. When the dictionary is destroyed, or when the value for that key is overwritten, the memory must be freed.
As for the line:
*point = [touch locationInView:self.superview];
It takes the return value of locationInView: and stores it at the address pointed to by point. The "*" there is the dereferencing operator.
I am purely guessing here, given that the function is named "cache"BeginPointForTouches, it would appear that the purpose of this function is to create a dictionary of touches and cache them for fast lookup. Being a cache, it looks like it is the kind that keeps its memory around throughout the lifetime of the program and never frees itself. So to make sure, does this leak happen during the program or after the program exits? If after, then what I described is likely and isn't really a leak.