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.
Related
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]);
}
Currently, I have a need to store a potentially large amount of data (as doubles) in memory. I had originally created a NSObject container to store the data and added those to a NSMutableArray. However, this meant creating potentially thousands (or even hundreds of thousands) of NSObjects, the allocation of which was slowing everything down a lot. Moreover, all of those objects were eating up more memory than I'd like. This same data can be "easily" represented by a 3 dimensional c array to the effect of:
double data[fieldCount][dataAggregateCount][recordCount];
//Aggregate count is actually a static 6 at the moment, so it could be initialized:
double data[fieldCount][6][recordCount];
However, I can't really store that as an instance variable (that I know of). At present I do this:
#implementation MyClass{
double *_data;
}
And then malloc the data:
_data = malloc(sizeof(double) * fieldCount * 6 * recordCount);
However, to access the data, I've gotta do some particularly verbose math:
double value = _data[x + (y * fieldCount) + (z * fieldCount * aggregateCount)];
What I really want is to access the data like so: _data[x][y][z] but, of course, the compiler bitterly complains about that sort of notation on a double *.
Am I being unreasonable to expect I could store a variable multidimensional c-array as an instance variable without resorting to a continuous chunk of memory and manual offset calculations?
Just allocate a three-dimensional array...
/// Allocates a 2-dimensional double array.
double **doubleArray2(int y, int z)
{
double **a = malloc(sizeof(double *)*y);
if(!a) {
[NSException raise:#"no memory" format:#"haha-1"];
}
for(int i=0; i<y; i++)
{
a[i] = malloc(sizeof(double)*z);
if(!a[i]) {
[NSException raise:#"no memory" format:#"haha-2"];
}
}
return a;
}
/// Allocates a 3-dimensional double array.
double ***doubleArray3(int x, int y, int z)
{
double ***b = malloc(sizeof(double **)*x);
if(!b) {
[NSException raise:#"no memory" format:#"haha-3"];
}
for(int i=0; i<x; i++)
{
double **a = doubleArray2(y, z);
if(!a) {
[NSException raise:#"no memory" format:#"haha-4"];
}
b[i] = a;
}
return b;
}
have fun...
EDIT: and don't forget to deallocate the array properly when you're done ;)
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!
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)
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.