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)
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]);
}
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!
I'm using a 2D C array of ids in my iOS app. Is it possible to return this in an objective-C method? As an alternative solution, I tried to return a pointer to a 2D C array of integers, but I cannot modify the 2D-int array.
- (int (*)[8][8])board:(Piece *)piece
{
int (*layout)[8][8] = malloc(8 * 8 * sizeof(int));
//Cannot modify layout 2D C array
return layout;
}
I have some experience in Objective-C, but none in C. Am I likely to continually run into problems using C 2D arrays, such that I should make a 2D-Array Objective-C class? What is the more typical approach an iOS developer would use?
- (int **)board:(Piece *)piece
{
int **layout = malloc(8 * sizeof(int *));
for(int i=0; i<8; i++)
layout[i] = malloc(8 * sizeof(int));
return layout;
}
Don't forget to free the memory in the end. Also, you could also use a one dimensional array and something like this to access it in a similar way:
#define access(array, x, y) array[y * 8 + x]
There is also now drop in multi-dimensional array class in Objective-C, but you could create a NSArray with other NSArray's inside of it, or, google if someone else did this (I remember at least one implementation but can't recall its name)
After you declare int (*layout)[8][8] = malloc(8 * 8 * sizeof(int));, You can change the values like (*layout)[x][y]=val;. But I recommend you to declare int (*layout)[8], so you can access elements by simply layout[x][y]=val.
Edit: I don't know about Objective-C, but in C, the function I suggested will look like:
int (*newarray())[8] {
int (*l)[8]=malloc(64*sizeof(int));
// You can do stuff like l[2][4]=15 here
return l;
}
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);
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.