NSInteger = NSInteger -1? - objective-c

I am trying to do a very simple thing but I can't figure out how;
NSInteger * a=10;
a=a-1;
NSlog(#"a=%d",a);
For some reason it's showing a=6.
How can it be?

Your problem is that you've declared the variable a as a pointer.
Most Objective-C variables are pointers, but NSInteger is an exception, because it's just typedef'd to int or long.
Your code should look like this:
NSInteger a=10;
a=a-1;
NSlog(#"a=%d",a);
When you do math on a pointer, you are actually moving the location in memory it points to. For example if the size of an NSInteger is 4 (sizeof(NSInteger) == 4), moving it -1, or in other words, a one structure size back, the pointer gets decreased by 4.
This mechanique is heavily used in C when iterating arrays of structures, e.g.
CGPoint myPoints[4];
CGPoint* point = myPoints; //get the first point
for (NSUInteger i = 0; i < 4; i++) {
CGPoint currentPoint = *point;
point++; //moves to the next point, adding sizeof(CGPoint)
}
This is called pointer arithmetic and you can write it in different ways, e.g. pointer + 1 but also point[1] or 1[point] (the last two are actually equal to *(pointer + 1)).

Related

How to declare C style arrays in objective-c app?

I have two NSArrays, one of CLLocation and one of doubles (encased in objects) that I need to write to C vectors to draw a gradient MKPolyline as defined here (https://github.com/wdanxna/GradientPolyline). I tried to copy some of the code I saw there in preparation to call one of its functions:
points = malloc(sizeof(CLLocationCoordinate2D)*self.run.locations.array.count);
velocity = malloc(sizeof(float)*self.run.locations.array.count);
for(int i = 0; i<self.run.locations.array.count; i++){
points[i] = self.run.locations.array[i];
velocity[i] = [velocities[i] floatValue];
}
Here self.run.locations.array is an array of CLLocations.
Right now I can't even build the project because I have not declared the variables. But where/how do I declare these variables? I don't know C, and the project I am trying to use doesn't seem to include these declarations in a place I can find them.
points is an array of CLLocationCoordinate2D (dynamically allocated) so it should be a pointer to CLLocationCoordinate2D i.e.
CLLocationCoordinate2D *points;
velocity is an array of float so it should be declared as
float *velocity;
Alternatively you can do this
float velocity[];
if you prefer array syntax.

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.

NSLog an array of CGPoints

I have declared the following CGPoint :
CGPoint borderVertices[5000];
I have added all the values to the array if I may call it (or just a set), but now I was wondering if there is anyway I can NSLog these points or copy them to a file.
I have tried :
NSLog(#"vertices %#", NSStringFromCGPoint(borderVertices));
but I get an error.
What about:
for (NSUInteger i = 0; i < 5000; i++)
{
NSLog(#"vertices :%#", NSStringFromCGPoint(borderVertices[i]));
}
Arrays like in plain old c, needs to be iterated to print each value at it's index.
NSLog(#"vertices %#", NSStringFromCGPoint(borderVertices));
The above statement would have worked if borderVertices is of type CGPoint. But it is not, it is of type CGPoint[].
You could make an array like:
CGPoint borderVertices[5000];
float bVx[5000];
float bVy[5000];
And assign values to bVx and bVy with borderVertices.position.(x or y) in a loop and then whenever you need the coordinates... there you have it.

interacting with UIViews stored inside a NSMutableArray

a big noob needs help understanding things.
I have three UIViews stored inside a NSMutableArray
lanes = [[NSMutableArray arrayWithCapacity:3] retain];
- (void)registerLane:(Lane*)lane {
NSLog (#"registering lane:%i",lane);
[lanes addObject:lane];
}
in the NSLog I see: registering lane:89183264
The value displayed in the NSLog (89183264) is what I am after.
I'd like to be able to save that number in a variable to be able to reuse it elsewhere in the code.
The closest I could come up with was this:
NSString *lane0 = [lanes objectAtIndex:0];
NSString *description0 = [lane0 description];
NSLog (#"description0:%#",description0);
The problem is that description0 gets the whole UIView object, not just the single number (dec 89183264 is hex 0x550d420)
description0's content:
description0:<Lane: 0x550d420; frame = (127 0; 66 460); alpha = 0.5; opaque = NO; autoresize = RM+BM; tag = 2; layer = <CALayer: 0x550d350>>
what I don't get is why I get the correct decimal value with with NSLog so easily, but seem to be unable to get it out of the NSMutableArray any other way. I am sure I am missing some "basic knowledge" here, and I would appreciate if someone could take the time and explain what's going on here so I can finally move on. it's been a long day studying.
why can't I save the 89183264 number easily with something like:
NSInteger * mylane = lane.id;
or
NSInteger * mylane = lane;
thank you all
I'm really confused as to why you want to save the memory location of the view? Because that's what your '89183264' number is. It's the location of the pointer. When you are calling:
NSLog (#"registering lane:%i",lane);
...do you get what's actually being printed out there? What the number that's being printed means?
It seems like a really bad idea, especially when if you're subclassing UIView you've already got a lovely .tag property which you can assign an int of your choosing.
You're making life infinitely more complex than it needs to be. Just use a pointer. Say I have an array containing lots of UIViews:
UIView *viewToCompare = [myArray objectAtIndex:3];
for (id object in myArray) {
if (object == viewToCompare) {
NSLog(#"Found it!");
}
}
That does what you're trying to do - it compares two pointers - and doesn't need any faffing around with ints, etc.

Problem while converting NSData to int

Using foundation and cocoa frameworks on Mac, I am trying to convert an NSData object in humanly understandable number.
Let say the NSData object is an image of NPIXEL. I know the binary data are coded in big endian and represent 32 bit integer (to be more precise 32 bit two complements integer). I write the piece of code bellow to convert the NSData into an int array. But the value I got are completely wrong (this does not means the measurement are bad, I used a special software to read the data and the value given by the software are different from the one I got with my code).
-(int *) GetArrayOfLongInt
{
//Get the total number of element into the Array
int Nelements=[self NPIXEL];
//CREATE THE ARRAY
int array[Nelements];
//FILL THE ARRAY
int32_t intValue;
int32_t swappedValue;
double Value;
int Nbit = abs(BITPIX)*GCOUNT*(PCOUNT + Nelements); Nbit/=sizeof(int32_t);
int i=0;
int step=sizeof(int32_t);
for(int bit=0; bit < Nbit; bit+=step)
{
[Img getBytes:&swappedValue range:NSMakeRange(bit,step)];
intValue= NSSwapBigIntToHost(swappedValue);
array[i]=intValue;
i++;
}
return array;
}
This piece of code (with minor change) work perfectly when the binary data represent float or double, but I dont when it is 16,32 or 64 bit integer. I also tried changingNSSapBigIntToHostintoNSSwapLittleInttoHost`. I even tried with long, but the results is still the same, I got bad values. What wrong I am doing ?
PS: Some of the variable in my code are already set elsewhere in my program. BITPIX is the bit size of each pixel. In this case 32. GCOUNT is equal to 1, PCOUNT 0 and Nelements is the total number of pixel I should have in my image.
Returning a pointer to a local variable is a very bad idea. array could get overwritten at any time (or if you were to write through the pointer, you could corrupt the stack). You probably want something like:
// CREATE THE ARRAY
int *array = malloc(Nelements * sizeof(int));
Your algorithm seems a bit overkill, too. Why not just copy out the whole array from the NSData object, and then byteswap the entries in place? Something like:
int32_t length = [Img length];
int32_t *array = malloc(length);
[Img getBytes:array length:length];
for (i = 0; i < length/sizeof(int32_t); i++)
{
array[i] = NSSwapBigIntToHost(array[i]);
}