Initi and write array in objective-c - objective-c

In my h file I declare a var that later should be an array:
#interface myClass : CCNode {
CGPoint *mVertices;
}
#end
In my init method:
mVertices = malloc(size * size * sizeof(CGPoint));
mVertices[0][0] = ccp(0,0);
At this last line I get an error Subscripted value is neither array nor pointer.
Why do I get this error and how to solve that problem?

mVertices is a pointer, but you treat it like a two-dimensional array which is not allowed (you may treat it like a one-dimensional array, though).
Creating a dynamic multi-dimensional array in (Objective)-C is tricky insofar as the compiler would need to know the size of all but the first dimension to actually compile where in memory the element is situated.
But you can do the calculation yourself:
mVertices[(row * size) + column] = ccp(row, column);
You might want to define a macro for that:
#define VERTICE_ACCESS(row,colum) mVertices[(row * size) + column]

Your array is not two dimensional. It's just a list of vertices.
If you want to allocate space for a dynamic two dimensional array in C you could do:
CGPoint** mVertices;
NSInteger nrows = 10;
NSInteger ncolumns = 5;
mVertices = calloc(sizeof(CGPoint*), nrows);
if(mVertices == NULL){NSLog(#"Not enough memory to allocate array.");}
for(NSUInteger i = 0; i < nrows; i++)
{
mVertices[i] = calloc(sizeof(CGPoint), ncolumns);
if(mVertices[i] == NULL){NSLog(#"Not enough memory to allocate array.");}
}
mVertices[0][5] = CGPointMake(12.0, 24.0);
mVertices[1][5] = CGPointMake(22.0, 24.0);
mVertices[2][5] = CGPointMake(32.0, 24.0);
mVertices[2][1] = CGPointMake(32.0, 24.0);
for(NSUInteger i = 0; i < nrows; i++)
{
for (int k = 0; k < ncolumns; k++)
{
NSLog(#"Point %#", NSStringFromPoint(NSPointFromCGPoint(mVertices[i][k])));
}
}
I used calloc instead of malloc to get CGPoints initialized with 0.0.

Related

Properly declare 2D array of Ints [duplicate]

I have the following code which works fine...
int testarr[3][3] = {
{1,1,1},
{1,0,1},
{1,1,1}
};
[self testCall: testarr];
Which calls this function:
- (void)testCall: (int[3][3]) arr {
NSLog(#"cell value is %u",arr[1][1]);
}
I need the array to be of variable length - What is the best way to declare the function?
Using blanks doesn't work:
- (void)testCall: (int[][]) arr {
Thanks for your help.
I would write this as:
- (void) testCall: (int *) aMatrice;
Doing so allows you to avoid multiple mallocs and the math to calculate a single offset in a linear array based on x, y coordinates in a 2D array is trivial. It also avoids the multiple mallocs implied by int** and the limitations of 2D array syntax perpetuated by the language.
So, if you wanted a 4x5 array, you might do:
#define WIDTH 4
#define HEIGHT 5
#define INDEXOF(x,y) ((y*WIDTH) + x)
int *myArray = malloc(sizeof(int) * 5 * ELEMS_PER_ROW);
You could then initialize the array linearly or with a nested for loop:
for(int x=0; x<width; x++)
for(int y=0; y<height; y++)
myArray[INDEXOF(x,y)] = ... some value ...;
And you would pass it to the method like:
[foo testCall: myArray];
Though you might want to also carry along the width and the height or, better yet, create a IntMatrix subclass of NSObject that wraps all of the pointer arithmetic and storage beyond a nice clean API.
(all code typed into SO)
C arrays can't be variable in more than one dimension.
You can't have this:
int testarr[][] = {
{1,1,1},
{1,0,1,2},
{1,1}
};
But you can have this:
int testarr[][3] = {
{1,1,1},
{1,0,1},
{1,1,1},
{4,5,6},
{7,8,9}
}
foo(testarr);
void foo(int param[][3])
{
printf("%d", param[3][1]); // prints 5
}
You can't use int[][] because the size of the second dimension affects how the array is laid out in memory. If you know the second dimension you can use int[][x], otherwise you'll have to use int** which can be accessed just like an array.
Why don't you just use NSArray or NSMutableArray with NSIntegers? Those array classes are of variable length, and much easier to use.
This would result in
- (void)testCall: (NSArray *) arr {
NSLog(#"cell value is %u", [[arr objectAtIndex:1] objectAtIndex:1]);
}
(Of course, you would also have to define testarr using NSArray.)
If you really want to use C arrays, making the method argument a pointer to an int with
- (void)testCall: (int*) arr {
will probably work (with the rest of the code staying the same).
call
int testarr[3][3] = {
{1,1,1},
{1,0,1},
{1,1,1}
};
[self testCall: (int *)testarr];
function
- (void)testCall: (int *) arr
{
int (*V_arr)[3] = (int(*)[3])arr;
NSLog(#"cell value is %u",V_arr[1][1]);
}

Empty float ** for sound samples

I have been attempting to pass and array to a method within DiracLE audio library.
The array looks like this in the debugger
- (OSStatus) readFloatsConsecutive:(SInt64)numFrames intoArray:(float**)audio withOffset:(long)offset
That fills the array up like so
if (audio) {
for (long c = 0; c < mExtAFNumChannels; c++) {
if (!audio[c]) continue; // this executes for both channels
// but doesnt proceed into next for loop
for (long v = 0; v < numFrames; v++) {
if (v < loadedPackets) audio[c][v+offset] = (float)data[v*mExtAFNumChannels+c] / 32768.f;
else audio[c][v+offset] = 0.f;
}
}
}
I call it like this
[reader readFloatsConsecutive:frameCount intoArray:arrayToFill];
arrayToFill being an argument to the current function scope
[self readAudioDataForFile:temp withArray:tempArray];
The array was initially passed into the function like this
// this array was passed into the function as tempArray which is float **tempArray = NULL;
arrayToFill = (float **) malloc ( (frameCount * channelCount) * sizeof( float ));
As I needed to extract audio data from the file in my method I have to malloc the array there and pass it into the dirac function for filling. I malloc like so arrayToFill = (float **) malloc ( (frameCount * channelCount) * sizeof( float )); and then pass it to the dirac function as mentioned before.
This array could be a 2 dimensional or 1 dimensional array depending on channel count
The problem relies on allocation in my opinion.
Allocating a 1 dimensional array would look like:
arrayToFill = (float *) malloc ( (frameCount * channelCount) * sizeof( float ));
and it would be enought.
Allocating a 2 dimensional array would be different though, because you have to allocate even inner arrays. If I understood correctly if you have two channels then the array is bidimensional, you should do something like:
arrayToFill = (float **)calloc(channelCount, sizeof(float*));
for (int i = 0; i < channelCount; ++i)
arrayToFill[i] = (float*)calloc(frameCount, sizeof(float));
This because you need to allocate a pointer to pointer to float. So in the first step you allocate a 2 dimensional array of pointers to float, these pointers are initialized to NULL so you have to loop through it and allocate them separately.
If the channel is inner inside the array (eg. the first index chooses the frame and not the channel) then you should swap dimensions.

The scripted value is neither an array nor a pointer

So I am trying to allocate memory for a 2D array of ints such that I can reference it outside of the loop in which the size is determined. (I have a scope issue because the size of the array isn't fixed.)
So this was the proposed solution, but I am getting the error "The scripted value is neither an array nor a pointer". Anyone know what I am doing wrong?
//M and m are just 2 int numbers
int X = self.create2dArray(M,m);
for(int kk = 0; kk < M; kk++)
{
for (int kk1 = 0; kk1 < m; kk1++)
{
//small "x" is an NSMutableArray of NSNumbers. So I am just running the 2 for loops to fill the whole 2D array
X[kk][kk1] = [[x objectAtIndex: (kk + kk1 * J)] intValue]; //ERROR Line
}
}
//outside of Main
static inline int **create2dArray(int w, int h)
{
size_t size = sizeof(int) * 2 + w * sizeof(int *);
int **arr = malloc(size);
int *sizes = (int *) arr;
sizes[0] = w;
sizes[1] = h;
arr = (int **) (sizes + 2);
for (int i = 0; i < w; i++)
{
arr[i] = calloc(h, sizeof(**arr));
}
return arr;
}
I believe that first line should start with int** X instead of int X
Okay, so your problem may most likely lie within your manually allocating of the memory for the integers. My proposed solution is to just fill it up with random "filler" numbers, for instance: 0. By doing so, you don't risk messing up the allocation process. In addition, it's much easier and it works given you'll be filling it up with integers later on. Hope this helped!

2D Array Declaration - Objective C

Is there a way to declare a 2D array of integers in two steps? I am having an issue with scope. This is what I am trying to do:
//I know Java, so this is an example of what I am trying to replicate:
int Array[][];
Array = new int[10][10];
Now, in OBJ-C I want to do something similar, but I cant get the syntax right. Right now I have it in one step, but I cannot use it outside of the If-Statement in which I currently have it:
int Array[10][10]; //This is based on an example I found online, but I need
//to define the size on a seperate line than the allocation
Can anyone help me out with this? I know its probably a more basic question, but you can't use the keyword "new" outside of a message (to my knowledge) and you cant send messages to ints. :(
*EDIT 1:**
My problem is scope related.
//Declare Array Somehow
Array[][] //i know this isn't valid, but I need it without size
//if statement
if(condition)
Array[1][2]
else
Array[3][4]
//I need to access it outside of those IFs
//... later in code
Array[0][0] = 5;
This is my preferred way of creating a 2D array, if you know the size of one of the boundaries:
int (*myArray)[dim2];
myArray = calloc(dim1, sizeof(*myArray));
And it can be freed in one call:
free(myArray);
Unfortunately, one of the bounds MUST be fixed for this to work.
However, if you don't know either of the boundaries, this should work too:
static inline int **create2dArray(int w, int h)
{
size_t size = sizeof(int) * 2 + w * sizeof(int *);
int **arr = malloc(size);
int *sizes = (int *) arr;
sizes[0] = w;
sizes[1] = h;
arr = (int **) (sizes + 2);
for (int i = 0; i < w; i++)
{
arr[i] = calloc(h, sizeof(**arr));
}
return arr;
}
static inline void free2dArray(int **arr)
{
int *sizes = (int *) arr;
int w = sizes[-2];
int h = sizes[-1];
for (int i = 0; i < w; i++)
free(arr[i]);
free(&sizes[-2]);
}
The declaration you showed (e.g. int Array[10][10];) is OK, and will be valid for the scope it was declared to, if you do it in a class scope, then it will be valid for the whole class.
If the size of the array varies, either use dynamic allocation (e.g. malloc and friends) or use NSMutableArray (for non-primitive data types)

Shuffling an array of NSNumbers & converting back to ints

I have an NSMutableArray urlArray of size n, I want to randomly choose 4 of these URLs from the total number of elements in the array.
However I don't want to shuffle urlArray directly, I'd prefer to make an "indexArray" [0 ... (n-1)] & shuffle these, & then use the first 4 elements of the shuffled indexArray to decide which elements I choose from urlArray.
First off I created the indexArray as follows:
for (int i = 0; i < numberOfStems; i++) {
[indexArray addObject:[NSNumber numberWithInteger:i]];
}
This allowed me to shuffle my indexArray, so far so good. Because I used the
[NSNumber numberWithInteger:i] method, the elements in the shuffled indexArray are NSNumbers.
Is there a way to convert the NSNumber objects in indexArray into ints?
I attempted to use the intValue function but this didn't appear to be what I needed.
I also tried creating a c style array but that wasn't so successful either - I'd like to stick with objective-c syntax if possible.
Any ideas? any hints appreciated :)
Why don't you just create a normal c array, shuffle that and then use the first four integers in the array as the for random index?
something like
int* index = malloc(numberOfStems*sizeof(int));
for (int i = 0; i < numberOfStems; ++i)
{
index[i] = i;
}
for (int i = numberOfStems - 1; i > 0; --i)
{
int randomIndex = arc4random() % i;
int tmp = index[i];
index[i] = index[randomIndex];
index[randomIndex] = tmp;
}
now use index to access the URL's
EDITED: updated algorithm (although not really related to OP question)
For a temporary array that stores only integers and gets thrown away after a relatively short task I would definitely prefer a C-style array: this would avoid a great deal of overhead, and is also simple to read.
int *array = (int*)malloc(sizeof(int)*numberOfStems);
for (int i = 0 ; i != numberOfStems ; i++) {
array[i] = i;
}
// Do the shuffle
// Pick first four, and do whatever you need to do
// ...
// Now that you are done with the array, do not forget to free it:
free(array);