Hello stackoverflow fellow members?
Struct Declaration in class A
struct PointSprite
{
GLfloat x;
GLfloat y;
GLfloat size;
Color4f color;
} ParticleSystems[MAXIMUM_PARTICLES_ON_SCREEN];
// I generally put some stuffs in ParticleSystem array.
// for ex) struct PointSprite *ps = &ParticleSystems[index];
// and it works well on the class A, but I want to get class B to access this array.
My question is, how am I suppose be return the array of 'ParticlelSystems' array so that other class can access to it? I have tried below code to return the pointer, but compiler gives me a warning.
- (struct ParticleSystems *) commitParticles
{
struct ParticleSystems *ptr = &ParticleSystems; // it said, assigning incompatible pointer type
return ptr;
}
Or should I need to allocate the 'ParticleSystems' array? Please help ! Thanks
If you are creating the array inside the function then you should dynamically allocate it using new and then return a pointer to it.
You cannot return arrays from a function, you will have to return a pointer to it.
Sample Code:
ParticleSystems* doSomethingInteresting()
{
ParticleSystems *ptr = new ParticleSystems[MAXIMUM_PARTICLES_ON_SCREEN];
//do the processing
return ptr;
}
The caller takes the ownership of the returned dynamically allocated array and needs to deallocate it to avoid memory leaks:
delete []ptr;
You can either return it, after allocating one, or you can fill one passed to you by the user. The latter leaves the responsibility to the user to provide a ParticleSystem to the method which receives the data. It can be a local array, or a malloced one.
- (void) commitParticles: (ParticleSystems *) sprites
{
// set members of the structs here
}
I prefer this kind of passing to returning a malloced array. Your mileage may vary.
You're getting the assigning incompatible pointer type compiler warning because your ptr declaration should be of type PointSprite *, not ParticleSystems *
Related
I bumped to a strange error.(at least for me) I am trying to use float array in FFT and audio filters that I apply. but float array gives different datas at the end.
I define a global pointer. I point a float array to it. but when I try to use the pointer in somewhere out of the scope of a method, the last 100-150 datas of 441000 datas get mostly 0 or some other very big numbers. I dont understand how a data can change when I use somewhere in out of scope
in scope I loop in it and every data is correct but when I try to loop outside of the scope of the method I created the array, it gives different datas at the end.
#interface ViewController ()
{
float *filteredData;
int theFileLengthInFrames;
}
#end
#implementation ViewController
..
..
-(void)FilterData:(float * ) rawData
{
int count = theFileLengthInFrames;
float filteredRawData[count];
for (int i = 0; i<count; i++)
{
filteredRawData[i] = rawData[i];
printf("%d_%f ",i,filteredRawData[i]);
//I check here to see the data . In here it is normal
}
filteredData = filteredRawData;
}
-(void) CalculateFFT
{
int numSamples = theFileLengthInFrames;
for (int i = 0; i<numSamples; i++)
{
printf("%d_%f ",i,filteredData[i]);
//when I check here to see the data , the last around 100 data are 0.00000 or some big number such as 250399682724883753288597504.000000
}
}
need help thanks
Your FilterData: method points the instance variable filteredData to a local array filteredRawData. Since filteredRawData is allocated on the stack, it becomes invalid when FilterData: returns. Then filteredData is a dangling pointer, and using it results in undefined behavior.
Solution: allocate persistent storage for filteredData. I would do it like this:
#implementation ViewController {
NSMutableData *filteredDataStorage;
float *filteredData;
}
-(void)FilterData:(float * ) rawData {
int count = theFileLengthInFrames;
filteredDataStorage = [NSMutableData dataWithLength:count * sizeof *rawData];
filteredData = (float *)filteredDataStorage.mutableBytes;
for (int i = 0; i<count; i++) {
filteredRaw[i] = rawData[i];
printf("%d_%f ",i,filteredRawData[i]);
//I check here to see the data . In here it is normal
}
}
Using NSMutableData for the persistent storage lets ARC take care of deallocating it when you call FilterData: again, or when ViewController is deallocated.
filteredData - The float pointer is an ivar, it's scoped to your object instance.
filteredRawData is defined at method scope. It's an array located on the stack. When filteredRawData goes out of scope that memory is no longer valid. Reading from it is undefined at best and could result in an access violation. You probably want to use malloc to dynamically allocate memory for your data, or have a global buffer defined for you to play with.
How to return a C-style array of integers from an Objective-C method? This is what my code looks like so far:
Function call:
maze = [amaze getMaze];
Function:
-(int*) getMaze{
return maze;
}
I just started writing in Objective-C today so this is all new to me.
In C if you need to return an array from a function, you need to allocate memory for it using malloc and then return the pointer pointing to the newly allocated memory.
Once you're done working with this memory you need to free it.
Something like:
#include <stdlib.h> /* need this include at top for malloc and free */
int* foo(int size)
{
int* out = malloc(sizeof(int) * size); /* need to get the size of the int type and multiply it
* by the number of integers we would like to return */
return out; /* returning pointer to the function calling foo().
* Don't forget to free the memory allocated with malloc */
}
int main()
{
... /* some code here */
int* int_ptr = foo(25); /* int_ptr now points to the memory allocated in foo */
... /* some more code */
free(int_ptr); /* we're done with this, let's free it */
...
return 0;
}
This is as C style as it gets :) There are probably other (arguably more suitable) ways to do this in Objective C. However, as Objective C is considered a strict superset of C, this would also work.
If I may further expand on the need to do this by pointers. C-style arrays allocated in a function are considered local, once the function is out of scope they are automatically cleaned up.
As pointed out by another poster, returning a standard array (e.g. int arr[10];) from a function is a bad idea as by the time the array is returned it no longer exists.
In C we get around this problem by allocating memory dynamically using malloc and having a pointer that points to that memory returned.
However unless you free this memory adequately, you may introduce a memory leak or some other nasty behavior (e.g. free-ing a malloc-ed pointer twice will produce unwanted results).
Given you explicitly ask about C-style arrays no suggestions here that you should use NSArray etc.
You cannot return a C-style array directly (see below) as a value in Objective-C (or C or C++), you can return a reference to such an array.
Types such as int, double and struct x can all be passed by value - that is the actual bits representing the value are passed around. Other things; such as C-style arrays, dynamically allocated memory, Objective-C style objects, etc.; are all passed by reference - that is a reference to a location in memory that contains the actual bits the represent the value is passed around.
So to return a C-style array from a function/method you can:
Dynamically (malloc et al) an array and return the reference to the allocated memory;
Pass in a reference to an already existing array and have the function fill it up; or
Wrap the array up as a struct...
The normal choices are (1) or (2) - note you cannot return a reference to a stack allocated array, as in:
int *thisIsInvalid()
{
int myValues[5];
...
return myValues; // will not work, the type is correct but once function
// returns myValues no longer exists.
}
If you really want to return a (small) array by value you can actually do it using (3). Remember that struct values are passed by value. So the following will work:
typedef struct
{
int array[5];
} fiveInts;
fiveInts thisIsValid()
{
fiveInts myValues;
...
myValues.array[3] = ...; // etc.
...
return myValues;
}
(Note that there is no overhead from wrapping the array inside a struct when it comes to reading/writing the array - the cost in the above is copying all the values back - hence only advised for small arrays!)
HTH
- (NSArray *)toArray:(int *)maze {
NSMutableArray *retVal = [[NSMutableArray alloc] init];
for (int c = 0; maze[c] != NULL; c++) {
[retVal addObject:[NSNumber numberWithInt:maze[c]]];
}
return [retVal array];
}
I've never been comfortable passing mutable data in and out of methods and not sure why. If you need to change the values later, send the array a mutableCopy message.
you can do it in this way
- (void)getArray:(int *)array withLength:(NSUInteger)length{
for (int i = 0; i < length; i++)
array[i] = i;
}
int array[3];
[object getArray:array withLength:3];
NSLog(#"%d %d %d", array[0], array[1], array[2]); // 1 2 3
I want to do achieve something like this in Objective-C
+(int[10][10])returnArray
{
int array[10][10];
return array;
}
However, this gives an "array initializer must be an initializer list" compiler error. Is this at all possible?
You can't return an array (of any dimension) in C or in Objective-C. Since arrays aren't lvalues, you wouldn't be able to assign the return value to a variable, so there's no meaningful for such a thing to happen. You can work around it, however. You'll need to return a pointer, or pull a trick like putting your array in a structure:
// return a pointer
+(int (*)[10][10])returnArray
{
int (*array)[10][10] = malloc(10 * 10 * sizeof(int));
return array;
}
// return a structure
struct array {
int array[10][10];
};
+(struct array)returnArray
{
struct array array;
return array;
}
Another way you can do it with objective C++, is to declare the array as follows:
#interface Hills : NSObject
{
#public
CGPoint hillVertices[kMaxHillVertices];
}
This means the array is owned by the Hills class instance - ie it will go away when that class does. You can then access from another class as follows:
_hills->hillVertices
I prefer the techniques Carl Norum describes, but wanted to present this as an option that might be useful in some cases - for example to pass data into OpenGL from a builder class.
I have a struct Position, like this:
typedef struct Position { int x, y; } Position;
How may I pass it in NSObject performSelector:withObject:afterDelay:? Like this:
Position pos;
pos.x = pos.y = 1;
[self performSelector:#selector(foo:)
withObject:pos // ERROR
afterDelay:5.0f];
EDIT: changed code to fix typo
Uhm.. use a CGPoint and something like
[self performSelector:#selector(foo:)
withObject:[NSValue valueWithCGPoint:CGPointMake(pos.x, pos.y)]
afterDelay:5.0f];
And read it again as
NSValue v;
CGPoint point = [v CGPointValue];
or leave the Position class away completely, CGPoint does the same
You could wrap your custom type using NSValue class. The error is that you didn't provide an object reference to the method.
Try using NSValue's +(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type; class method. On the other side you can retrieve the value using -(void)getValue:(void *)buffer;.
preformSelector:withObject: accepts only objects as parameters, hence you'll have to implement your foo: method to accept an object. There are two ways to pass the struct as an object:
create a struct-like object or
wrap it into NSValue and unwrap it in the method.
Full answer, based on user756245's (which doesn't tell you how to use it, not a great deal of help). Also, Apple suggests you use a slightly different method these days, IIRC:
typedef myStruct { int a; } myStruct;
myStruct aLocalPointer = ... assign to it
[self performSelector:#selector(myOtherMethod:) withObject:[NSValue value:&aLocalPointer withObjCType:#encode(myStruct)] afterDelay:0.25];
This is most likely asking for trouble, but you can pass CGPoint as id by bridging it in this way:
withObject:(__bridge id)((void *)(&point))
This will lead to a crash if point goes out of scope and your selector tries to read it, though.
I have an array of pointers to Objective-C objects. These objects have a sort key associated with them. I'm trying to use qsort to sort the array of pointers to these objects. However, the first time my comparator is called, the first argument points to the first element in my array, but the second argument points to garbage, giving me an EXC_BAD_ACCESS when I try to access its sort key.
Here is my code (paraphrased):
- (void)foo:(int)numThingies {
Thingie **array;
array = malloc(sizeof(deck[0])*numThingies);
for(int i = 0; i < numThingies; i++) {
array[i] = [[Thingie alloc] initWithSortKey:(float)random()/RAND_MAX];
}
qsort(array[0], numThingies, sizeof(array[0]), thingieCmp);
}
int thingieCmp(const void *a, const void *b) {
const Thingie *ia = (const Thingie *)a;
const Thingie *ib = (const Thingie *)b;
if (ia.sortKey > ib.sortKey) return 1; //ib point to garbage, so ib.sortKey produces the EXC_BAD_ACCESS
else return -1;
}
Any ideas why this is happening?
The problem is two fold:
the first argument to qsort needs to be a pointer to the beginning of the array
the arguments passed to your sort function are actually pointers to the pointers of your data
Consider this working code:
int thingieCmp(const void *a, const void *b) {
NSObject *aO = *(NSObject **)a;
NSObject *bO = *(NSObject **)b;
if (aO.hash > bO.hash) return 1;
else return -1;
}
int main (int argc, const char * argv[]) {
NSObject **array;
array = malloc(sizeof(NSObject*)*20);
for(int i = 0; i < 20; i++) {
array[i] = [NSObject new];
}
qsort(array, 20, sizeof(NSObject*), thingieCmp);
return 0;
}
Note that the comparison function resolves the data pointers by NSObject *aO = *(NSObject **)a and the qsort function takes array as an argument directly.
All of this, though, begs the question of Why bother?
NSArray is very good at holding arrays of objects and is quite conveniently sortable. Performance is excellent in the general case. If performance analysis indicates that it isn't, you can optimize it away relatively easily.
Note, also, that I have been consistent in use of sizeof() -- same type in both places. Also, the const in your original code is not necessary.
I think, one mistake lies right in the line
qsort(array[0], numThingies, sizeof(array[0]), thingieCmp);
Try
qsort(&array[0], numThingies, sizeof(array[0]), thingieCmp);
or even
qsort(array, numThingies, sizeof(array[0]), thingieCmp);
instead. The compiler won't complain here, as qsort is supposed to take a void* and you pass it a Thingy* which can legally be cast to void* without warning, but you really want qsort to operate on the entire array, which has type Thingy**.
Another thing is: the comparator will be called with pointers to the array slots as arguments, so what you get is actually a Thingy**:
int
thingieCmp(void* a, void* b)
{
Thingie *ia = *((Thingie**)a);
Thingie *ib = *((Thingie**)b);
...
}