A pointer to pointer in a struct C/ObjC - objective-c

typedef struct {
float Position[3];
float Color[4];
float VertexNormal[3];
} Vertex;
typedef struct WingedEdge{
struct WingedEdge* sym;
struct WingedEdge* next;
struct WingedEdge* prev;
Vertex** vertex;
GLushort** indexPointer;
} WingedEdge;
Vertex* vertices;
GLushort* indices;
struct WingedEdge* wingedEdges;
int numberOfVertices; //initialized elsewhere
int numberOfIndices; //initialized elsewhere,this is multiplied by three since I am not using a struct for the indices
vertices = (Vertex *) malloc(numberOfVertices * sizeof(Vertex));
indices = (GLushort *) malloc(numberOfIndices * sizeof(GLushort) * 3);
wingedEdges = (struct WingedEdge*)malloc(sizeof(struct WingedEdge)*numberOfIndices*3);
for (int i = 0; i < numberOfIndices*3; i+=3) {
wingedEdges[i].indexPointer = (&indices+i);
wingedEdges[i+1].indexPointer = (&indices+i);
wingedEdges[i+2].indexPointer = (&indices+i);
wingedEdges[i].vertex = (&vertices+indices[i]);
wingedEdges[i+1].vertex = (&vertices+indices[i+1]);
wingedEdges[i+2].vertex = (&vertices+indices[i+2]);
NSLog(#"%hu %hu %hu", *(indices+i),*(indices+i+1),indices[i+2]);
NSLog(#"%f %f %f", (vertices+indices[i])->Position[0], (vertices+indices[i])->Position[1], (vertices+indices[i])->Position[2]);
NSLog(#"%f %f %f", (vertices+indices[i+1])->Position[0], (vertices+indices[i+1])->Position[1], (vertices+indices[i+1])->Position[2]);
NSLog(#"%f %f %f", (vertices+indices[i+2])->Position[0], (vertices+indices[i+2])->Position[1], (vertices+indices[i+2])->Position[2]);
NSLog(#"%hu", **(wingedEdges[i].indexPointer));
}
Tried looking at a few other problems with pointers and structs but I did not find anything. I am getting an error with the last NSLog call. Everything thing in the NSLog calls with indices and vertices is correct so it looks like it might be a simple syntax error or pointer issue. Also, how would I increment the pointer that indexPointer points to? Since indexPointer points to a indices pointer, then I want to access indices+1 and indices+2 as well through indexPointer.

(&indices+i) doesn't point to any memory you have allocated.
What will work is to change the indexPointer and vertex to single pointers and then
wingedEdges[i].indexPointer = &indices[i];
wingedEdges[i].vertex = &vertices[indices[i]];
Then *(wingedEdges[i].indexPointer) is the same as indices[i] and
wingedEdges[i].vertex->Position[0] is the same as vertices[indices[i]].Position[0]. However, you will not get the automatic updating that you want (see my comments for more details). I recommend a simple inline function:
inline *Vertex vertex(WingedEdge* e)
{
return &vertices[*(e->indexPointer)];
}

Related

Incompatible block pointer type initializing float

Im not sure how to get this to work: I was thinking something to do with typedef, but I can't find much on the subject.
float (^pixelsToDistance)(float, float, NSString *) = ^(float distance, float scale, NSString *conversion)
{
// Code goes here
}
Im trying to return a float value from this block function.
Should I use a function instead?
You were close. You want:
float (^pixelsToDistance)(float, float, NSString *) = ^float(float distance, float scale, NSString *conversion) { ... };
Note the return type after the ^ on the right hand side of the assignment operator.
As the commentator points out, you can omit the return type if it's clear to the compiler what you're returning from the block. E.g.:
float (^pixelsToDistance)(float, float, NSString *) = ^(float distance, float scale, NSString *conversion) { return 0.0f };

Passing array of float pointers into VBO

I'm creating a particle system renderer, the problem is that all my particle positions are encapsulated into classes that integrate them over time and do some other stuff. Instead of copying the values into a separate array to render each frame, I created a point struct like this that I can use to point to all the values once:
typedef struct
{
float *x, *y, *z;
} point;
I then malloc an array of these the same size as my array of particles.
Declaration at the top:
point *points;
Malloc:
points = malloc(sizeof(point) * [particles count]);
I then loop through all the particles and copy the addresses of each position to the corresponding pointer so:
for (int i = 0; i < [particles count]; ++i)
{
points[i].x = &[[particles objectAtIndex:i] getPosition].x;
points[i].y = &[[particles objectAtIndex:i] getPosition].y;
points[i].z = &[[particles objectAtIndex:i] getPosition].z;
}
My get position function just returns a vector struct (float x, y, z).
The first problem I encountered with this is that when I display the values like so:
NSLog(#"%f", *points[0].x);
Instead of reading of the value (say: 0.5), it displays it rounded and negated (so: -1.0).
I then get the data into my VBO like this:
glBufferData(GL_ARRAY_BUFFER, sizeof(point) * [particles count], &points[0], GL_DYNAMIC_DRAW);
I think this is also wrong but can't find any information on how to pass pointers into VBOs.
What you're doing is wrong because in C everything is passed by value, so when you dereference the .x member of the returned struct, you're doing it on a copy of the position struct, which will be popped from the stack if not assigned to any value.
You're design is wrong, you don't need a struct like this one:
typedef struct
{
float *x, *y, *z;
} point;
Rather one like this:
typedef struct
{
float x,y,z;
}
If you still want to assign it to it's original value, in a way that if the original struct's values change, also this struct is changed, then you need a getter who will return a pointer to the struct, and hold a pointer to it:
points[i] = [[particles objectAtIndex:i] getPositionPointer];
This way you're sure that your struct contains the same values of the original struct, but you're violating encapsulation. Which makes me think that maybe you don't really need to hold a pointer to original struct, but if there's a reason to do then I've shown you the way.

Objective-c: Adding a custom object to a NSMutableArray

I usually program in java or c++ and I recently started with objective-c. Looking for vectors in objective-c, I found NSMutableArray which seems to be the best option. I'm working on an opengl game and I'm trying to create an NSMutableArray of textured quads for my sprites. Here is the relevant code:
I define textured quads:
typedef struct {
CGPoint geometryVertex;
CGPoint textureVertex;
} TexturedVertex;
typedef struct {
TexturedVertex bl;
TexturedVertex br;
TexturedVertex tl;
TexturedVertex tr;
} TexturedQuad;
I create an array in the interface:
#interface Sprite() {
NSMutableArray *quads;
}
I initiate the array and I create the texturedQuads based on "width" and "height", which are the dimensions of a single sprite, and "self.textureInfo.width" and "self.textureInfo.height", which are the dimensions of the entire sprite sheet:
quads = [NSMutableArray arrayWithCapacity:1];
for(int x = 0; x < self.textureInfo.width/width; x++) {
for(int y = 0; y < self.textureInfo.height/height; y++) {
TexturedQuad q;
q.bl.geometryVertex = CGPointMake(0, 0);
q.br.geometryVertex = CGPointMake(width, 0);
q.tl.geometryVertex = CGPointMake(0, height);
q.tr.geometryVertex = CGPointMake(width, height);
int x0 = (x*width)/self.textureInfo.width;
int x1 = (x*width + width)/self.textureInfo.width;
int y0 = (y*height)/self.textureInfo.height;
int y1 = (y*height + height)/self.textureInfo.height;
q.bl.textureVertex = CGPointMake(x0, y0);
q.br.textureVertex = CGPointMake(x1, y0);
q.tl.textureVertex = CGPointMake(x0, y1);
q.tr.textureVertex = CGPointMake(x1, y1);
//add q to quads
}
}
The problem is I don't know how to add the quad "q" to the array "quads". Simple writing [quads addObject:q] doesn't work because the parameter should be an id not a TexturedQuad. I've seen examples of how to make an id from an int etc, but I don't know how to do it with an object like my TexturedQuad.
The essence of it is that you wrap your C struct in an Obj-C class. The Obj-C class to use is NSValue.
// assume ImaginaryNumber defined:
typedef struct {
float real;
float imaginary;
} ImaginaryNumber;
ImaginaryNumber miNumber;
miNumber.real = 1.1;
miNumber.imaginary = 1.41;
// encode using the type name
NSValue *miValue = [NSValue value: &miNumber withObjCType:#encode(ImaginaryNumber)];
ImaginaryNumber miNumber2;
[miValue getValue:&miNumber2];
See here for more information.
As #Bersaelor pointed out, if you need better performance use pure C or switch to Obj-C++ and use vectors instead of Obj-C objects.
An NSMutableArray takes any NSObject* but not just structs.
If you're serious about programming in Objective-C, take a look at some tutorials.
Furthermore, NSMutableArrays are meant for convenience, if your adding/deleting a lot of objects to that Array, use plain C-stacks.
Especially for your use-case that more low-level approach will get better performance.
Keep in mind, Objective-C(++) is just a superset of C(++), so you can use any C(++) code you are already familiar with.
When I wrote my game tactica for iOS, I switched to C-Code whenever I had to do heavy lifting (i.e. recursive AI-functions that get called hundreds of times per second).

EXC_BAD_ACCESS when passing a pointer-to-pointer in a struct?

I've got a c-array of CGPoints in a struct. I need to replace this array when another CGPoint is added. I'd swear I'm doing this right and it seems to work fine a few times but eventually I'll get a EXC_BAD_ACCESS. What am I missing?
Here's the struct, which I've truncated to remove a lot of items that don't pertain.
typedef struct{
CGPoint **focalPoints;
NSUInteger focalPointCount;
CGRect boundingRect;
}FocalPoints;
Here's how I initialize it:
CGPoint *fPoints = (CGPoint *)malloc(sizeof(CGPoint));
FocalPoints focalInfo = {&fPoints, 0, rect};
Note that focalInfo is passed by reference to another function, like so: anotherFunction(&focalInfo).
Now here's the function that replaces the Points array with a new one:
void AddFocalPoint (CGPoint focalPoint, FocalPoints *focal){
if (focalPoint.x == CGFLOAT_MAX) return;
if (!CGRectContainsPoint(focal->boundingRect, focalPoint)) return;
int origCount = focal->focalPointCount;
int newCount = origCount + 1;
CGPoint *newPoints = (CGPoint *) malloc((newCount) * sizeof(CGPoint));
for (int i = 0; i < newCount; i++)
newPoints[i] = (i < origCount) ? *focal->focalPoints[i] : focalPoint; //error occurs here
free(*focal->focalPoints);
*focal->focalPoints = newPoints;
focal->focalPointCount = newCount;
}
The EXC_BAD_ACCESS error occurs in the above code on line 8: newPoints[i] = (i < origCount) ? *focal->focalPoints[i] : focalPoint;. So what exactly am I doing wrong?
This is a bit of a long shot, but maybe there's an issue with operator priority in *focal->focalPoints[i]. Have you try adding parentheses according to what you are trying to achieve ?
I believe the issue comes with where GCPoint *fPoints allocated as &fPoints evaluates to an address of that ... which is no longer valid once the function exits.
(The data to which it points was allocated fine with malloc.)
Aside from the suggestion I made in a comment, of using a linked list/NSMutableArray, my other suggestion would be that you use realloc() instead of constantly using malloc(), copying by hand, and then free()ing the old allocation.
void * realloc(void *ptr, size_t size);
The realloc() function tries to change the size of the allocation pointed to by ptr to size, and returns ptr. If there is not enough room to enlarge the memory allocation pointed to by ptr, realloc() creates a new allocation, copies as much of the old data pointed to by ptr as will fit to the new allocation, frees the old allocation, and returns a pointer to the allocated memory.
This is pretty much exactly what you are doing, but you can let the library handle it for you.
(May I also humbly suggest using the word "focal" slightly less to name variables in your function?) (Also also, I'm not really clear on why focalPoints in your struct is a pointer-to-pointer. You just want an array of structs -- a single pointer should be fine.)
Consider the following (somewhat extensive) rewrite; hope that it's helpful in some way.
typedef struct{
CGPoint *points; // Single pointer
NSUInteger count;
CGRect boundingRect;
} FocalPoints;
// Renamed to match Apple's style, like e.g. CGRectIntersectsRect()
void FocalPointsAddPoint (FocalPoints *, CGPoint);
void FocalPointsAddPoint (FocalPoints *f, CGPoint thePoint){
if (thePoint.x == CGFLOAT_MAX) return;
if (!CGRectContainsPoint(f->boundingRect, thePoint)) return;
NSUInteger origCount = f->count; // |count| is typed as NSUInteger; |origCount|
NSUInteger newCount = origCount + 1; // and |newCount| should be consistent
// Greatly simplified by using realloc()
f->points = (CGPoint *) realloc(f->points, newCount * sizeof(CGPoint));
(f->points)[newCount-1] = thePoint;
f->count = newCount;
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
// Just for testing; any point should be inside this rect
CGRect maxRect = CGRectMake(0, 0, CGFLOAT_MAX, CGFLOAT_MAX);
// Can initialize |points| to NULL; both realloc() and free() know what to do
FocalPoints fp = (FocalPoints){NULL, 0, maxRect};
int i;
for( i = 0; i < 10; i++ ){
FocalPointsAddPoint(&fp, CGPointMake(arc4random() % 100, arc4random() % 100));
NSLog(#"%#", NSStringFromPoint(fp.points[i]));
}
}
return 0;
}

calloc struct in C

I'm trying to initialize a pointer to a struct with 0.0 values in there. Look at the following situation:
typedef struct
{
float a;
float b;
float c;
} structA;
structA *ptr = calloc(100000, sizeof(structA));
I want all the values in *ptr be structA with initial values of {0.0, 0.0, 0.0}, but this is not I have now. Many of the indices of *ptr appear correctly, but some indices appear with weird values (like {0.0, 0.0, 10241256124.0}).
If I try malloc, the same thing happens.
What should I do?
You're doing something wrong... I've never used objective-c, so I stuck the code below into ideone.com and it worked as expected... (printing out done, not failed because) all values were zero'd. My guess is you're not checking properly, since it's quite unlikely there's a bug in your compiler...
#include <malloc.h>
typedef struct
{
float a;
float b;
float c;
} structA;
int main() {
int count = 100000;
int i;
structA *ptr = calloc(count, sizeof(structA));
if(ptr) {
for(i=0;i<count;i++) {
if(ptr[i].a || ptr[i].b || ptr[i].c) {
printf("fail\n");
}
}
printf("done\n");
}
return 0;
}