Multi-dimensional array access using pointer in C - c

Note that this has probably been answered before, but now in a way that I could understand it.
I'm trying to understand how pointers and arrays work together. I thought I understood both how and why 1D and 2D arrays could be accessed with pointers until I tried to wrap my head around 3D arrays (just to be clear, I understand 3D arrays, just not how to access them with pointers).
So let's say I have an array x[5] and I want to access the element x[1] using pointers. In that case, I can use *(&x[0]+1), because x is the same as &x[0] and *(x + 1) can be used to access a[1].
Now, for a 2D array, let's say it is declared as x[5][3].
To access x[1][2], I can use *(&x[0][0]+3*1+2). I can kind of understand this. We start at memory location x[0][0], then add 3 * 1 to get from x[0][0] to x[1][0], and then add 2 to get from x[1][0] to x[1][2].
The above makes sense to me until I get to a three dimensional array. Let's assume that x is declared as x[3][4][5], how would I get to, let's say element x[2][1][3] using the same logic(if possible)? Also, how can I apply this logic to higher dimensional arrays as well?
Any advice on this is greatly appreciated!

Supposing you have the following array:
//x[i][j][k]
int x[2][3][5] = { {{0,1,2,3,4},
{5,6,7,8,9},
{10,11,12,13,14}},
{{ 88,1,2,3,4 },
{ 5,6,7,8,9},
{ 10,11,12,77,14}}
};
Elements of 3D array are arranged in series in the memory like this:
{0,1,2,3,4},{5,6,7,8,9},{10,11,12,13,14},{ 88,1,2,3,4 },{ 5,6,7,8,9},{ 10,11,12,77,14}
Obviously, If you hava the address of the first element you can access the others by adding an offset. The address of the first element is **x, and the address of the next one is **x+1 and so forth. To access the elements of the x array look at the following example:
int D3_width = sizeof(x)/sizeof(x[0]); //2
int D2_width = sizeof(x[0]) / sizeof(x[0][0]); //3
int D1_width = sizeof(x[0][0]) / sizeof(int); //5
int i = 0, j = 2, k = 3;
cout << *(**x + i*D2_width*D1_width + j*D1_width + k);
output:13
You can use the same approach for other multi-dimensional arrays.
The formula is tested and works perfectly.

For a two-dimensional array you can skip through indexes of rows with pointer arithmetic as you were doing:
First index of first row + (length of row * desired Row)
If you are making your way up the dimensions, this expression will start to get rather large.
For 3D:
First index of first plane + (size of plane * desired plane)
Note that the plane is a 2-dimensional structure.
Now moving into 4D:
First index of first cube + (size of cube * desired cube )
Hope you get the idea.

Related

Seg faulting with 4D arrays & initializing dynamic arrays

I ran into a big of a problem with a tetris program I'm writing currently in C.
I am trying to use a 4D multi-dimensional array e.g.
uint8_t shape[7][4][4][4]
but I keep getting seg faults when I try that, I've read around and it seems to be that I'm using up all the stack memory with this kind of array (all I'm doing is filling the array with 0s and 1s to depict a shape so I'm not inputting a ridiculously high number or something).
Here is a version of it (on pastebin because as you can imagine its very ugly and long).
If I make the array smaller it seems to work but I'm trying to avoid a way around it as theoretically each "shape" represents a rotation as well.
https://pastebin.com/57JVMN20
I've read that you should use dynamic arrays so they end up on the heap but then I run into the issue how someone would initialize a dynamic array in such a way as linked above. It seems like it would be a headache as I would have to go through loops and specifically handle each shape?
I would also be grateful for anybody to let me pick their brain on dynamic arrays how best to go about them and if it's even worth doing normal arrays at all.
Even though I have not understood why do you use 4D arrays to store shapes for a tetris game, and I agree with bolov's comment that such an array should not overflow the stack (7*4*4*4*1 = 448 bytes), so you should probably check other code you wrote.
Now, to your question on how to manage 4D (N-Dimensional)dynamically sized arrays. You can do this in two ways:
The first way consists in creating an array of (N-1)-Dimensional arrays. If N = 2 (a table) you end up with a "linearized" version of the table (a normal array) which dimension is equal to R * C where R is the number of rows and C the number of columns. Inductively speaking, you can do the very same thing for N-Dimensional arrays without too much effort. This method has some drawbacks though:
You need to know beforehand all the dimensions except one (the "latest") and all the dimensions are fixed. Back to the N = 2 example: if you use this method on a table of C columns and R rows, you can change the number of rows by allocating C * sizeof(<your_array_type>) more bytes at the end of the preallocated space, but not the number of columns (not without rebuilding the entire linearized array). Moreover, different rows must have the same number of columns C (you cannot have a 2D array that looks like a triangle when drawn on paper, just to get things clear).
You need to carefully manage the indicies: you cannot simply write my_array[row][column], instead you must access that array with my_array[row*C + column]. If N is not 2, then this formula gets... interesting
You can use N-1 arrays of pointers. That's my favourite solution because it does not have any of the drawbacks from the previous solution, although you need to manage pointers to pointers to pointers to .... to pointers to a type (but that's what you do when you access my_array[7][4][4][4].
Solution 1
Let's say you want to build an N-Dimensional array in C using the first solution.
You know the length of each dimension of the array up to the (N-1)-th (let's call them d_1, d_2, ..., d_(N-1)). We can build this inductively:
We know how to build a dynamic 1-dimensional array
Supposing we know how to build a (N-1)-dimensional array, we show that we can build a N-Dimensional array by putting each (N-1)-dimensional array we have available in a 1-Dimensional array, thus increasing the available dimensions by 1.
Let's also assume that the data type that the arrays must hold is called T.
Let's suppose we want to create an array with R (N-1)-dimensional arrays inside it. For that we need to know the size of each (N-1)-dimensional array, so we need to calculate it.
For N = 1 the size is just sizeof(T)
For N = 2 the size is d_1 * sizeof(T)
For N = 3 the size is d_2 * d_1 * sizeof(T)
You can easily inductively prove that the number of bytes required to store R (N-1)-dimensional arrays is R*(d_1 * d_2 * ... * d_(n-1) * sizeof(T)). And that's done.
Now, we need to access a random element inside this massive N-dimensional array. Let's say we want to access the item with indicies (i_1, i_2, ..., i_N). For this we are going to repeat the inductive reasoning:
For N = 1, the index of the i_1 element is just my_array[i_1]
For N = 2, the index of the (i_1, i_2) element can be calculated by thinking that each d_1 elements, a new array begins, so the element is my_array[i_1 * d_1 + i_2].
For N = 3, we can repeat the same process and end up having the element my_array[d_2 * ((i_1 * d_1) + i_2) + i_3]
And so on.
Solution 2
The second solution wastes a bit more memory, but it's more straightforward, both to understand and to implement.
Let's just stick to the N = 2 case so that we can think better. Imagine to have a table and to split it row by row and to place each row in its own memory slot. Now, a row is a 1-dimensional array, and to make a 2-dimensional array we only need to be able to have an ordered array with references to each row. Something like the following drawing shows (the last row is the R-th row):
+------+
| R1 -------> [1,2,3,4]
|------|
| R2 -------> [2,4,6,8]
|------|
| R3 -------> [3,6,9,12]
|------|
| .... |
|------|
| RR -------> [R, 2*R, 3*R, 4*R]
+------+
In order to do that, you need to first allocate the references array (R elements long) and then, iterate through this array and assign to each entry the pointer to a newly allocated memory area of size d_1.
We can easily extend this for N dimensions. Simply build a R dimensional array and, for each entry in this array, allocate a new 1-Dimensional array of size d_(N-1) and do the same for the newly created array until you get to the array with size d_1.
Notice how you can easily access each element by simply using the expression my_array[i_1][i_2][i_3]...[i_N].
For example, let's suppose N = 3 and T is uint8_t and that d_1, d_2 and d_3 are known (and not uninitialized) in the following code:
size_t d1 = 5, d2 = 7, d3 = 3;
int ***my_array;
my_array = malloc(d1 * sizeof(int**));
for(size_t x = 0; x<d1; x++){
my_array[x] = malloc(d2 * sizeof(int*));
for (size_t y = 0; y < d2; y++){
my_array[x][y] = malloc(d3 * sizeof(int));
}
}
//Accessing a random element
size_t x1 = 2, y1 = 6, z1 = 1;
my_array[x1][y1][z1] = 32;
I hope this helps. Please feel free to comment if you have questions.

Multidimensional array : Split and put back together

I am trying to turn a 3 dimensional array "upside-down" as:
I have tried the inverse function, but if we look at the inverse operation in mathematical terms, it gives us another result. I need to turn without changing the data in the array. How to do that?
To split the 3-dimensional array (A x B x C) into A-sub-array (2d, B x C) I have used squeeze: k=squeeze(array(n,:,:)). Now I have a 2-dimensional array of size B x C. How to put it back together (in 3 dimensional array)?
You can use permute() to change the order of dimensions, which can be used as a multidimensional transpose.
Putting 2D matrices into a 3D one then is a simple indexing operation. Read more in indexing here.
A = rand(10,10,10);
B = permute(A, [ 3 2 1 ]); % Permute he order of dimensions
mat1 = rand(10,10);
mat2 = rand(10,10);
mat_both(:,:,2) = mat2; % Stack 2D matrices along the third dimension
mat_both(:,:,1) = mat1;
mat_both = cat(3,mat1, mat2); % Stacks along the third dimension in a faster way

Finding 2D array cell memory location

There is an array a[3][4] and we have to find the address of a[2][2] using row major order and 1001 as base address. I found 2 formulas do find the address:
For any array a[M][N] Row Major Order:
1) a[i][j] = Base Address+Datatype Size[(N*i)+j]
2) a[i][j] = Base Address+Datatype Size[N*(i-1)+(j-1)]
I tried both the formulas but the first one yielded the correct result but not the second one. Here is how I found the address of a[2][2] using row major order:
Using Formula 1:
a[2][2] = 1001+2[(4*2)+2]
= 1001+2[10]
= 1001+20
= 1021 (correct answer)
Using Formula 2:
a[2][2] = 1001+2[4*(2-1)+(2-1)]
= 1001+2[4+1]
= 1001+2[5]
= 1001+10
= 1011 (Wrong Answer)
Is there any error in my 2nd formula or have I done something wrong in the calculation using 2nd formula? Why aren't both the answers coming same?
as amit said, the equations are different, so they are not going to give the same result. when ever in doubt about a problem like this, try putting some numbers in the equations and try them out, so if we are trying for an array of size 4, at position 2,2
equation 1: (N * i) + j, (4 * 2) + 2 = 10
equation 2: N * (I - 1) + (j - 1) = 9
as you can see as they are not the same result, the problem is not in your code, but in the equation itself
if you are feeling brave, you can also try and prove it by induction as well
To find the memory address number, you will also need to know how much space an integer is occupying in memory as well. You can do this with sizeof(int);which will output how many bytes the integer is using on the system.
you will also need to know how an array of arrays is formatted in memory. Just like a normal array, and array of arrays is contiguous, meaning that there are no gaps in memory between the array elements. So an array a[2][2] {1,2}, {3,4} would be formatted like this. 1, 2, 3, 4.
using this you should be able to find the memory location with the following equation address location of array a[I][j] = B + W * [N * (I- Lr) + (J - Lc)] where:
B is the base address
I is the row subscript of the element you are looking for
J is the column element you are looking for
W is the size of an element
Lr is the lower limit of a row - 0 if not given
Lc is the lower limit of a column - 0 if not given
M is the number of rows of the matrix
N is the number of columns of the matrix

Indexing multidimensional arrays in C

I'm familiar with multidimensional arrays being accessed as such: arr[rows][cols] which makes sense to me when I imagine it as a grid or coordinate system and locating points. But I'm confused about the line below. I understand it is picking up a pointer to some struct located in the array of structures I just have a hard time imagining which location this could represent in terms of the coordinate system I'm used to...its a bitmap by the way and SOMETHING is a pixel.
//what does this line mean SOMETHING *o = original + row*cols + col;
for (row=0; row < rows; row++)
for (col=0; col < cols; col++) {
SOMETHING* o = original + row*cols + col;
SOMETHING* n = (*new) + row*cols + (cols-1-col);
*n = *o;
}
Think about how arrays are laid out in memory. A multidimensional array is just an array of arrays, so say you had an array like SOMETHING[10][10].
The memory layout would be:
[0][0], [0][1], .. [0][9], [1][0], [1][1].. [9][9]
This actually is exactly the same as allocating sizeof(SOMETHING)*100.
What the line SOMETHING* o = original + row*cols + col; is saying is "make a pointer to object of type SOMETHING".
The pointer address should be:
the memory address of original,
add row times cols to it,
which will place it at the start of a row,
then add the specific column to it
to get to the exact position of an object in the array
A two dimensional array such as:
{{00,01,02,03},
{10,11,12,13},
{20,21,22,23},
{30,31,32,33}}
Will be placed in memory in order. Just like this:
{00,01,02,03,10,11,12,13,20,21,22,23,30,31,32,33}
So, when you access the array with a[i][j], you can also access the array with
a + i *(ELEMENTS_IN_ROW) + j
There is a pointer named original which probably sits at the origin ([0][0]). You are doing simple arithmetic to point to the current co-ordinate.
Suppose it's a 5x5 array and you are now in the 3rd row, 4th column ([2][3])
To reach [2][3] from origin , you have to travel:
5 units in the first row
5 units in the second row
3 units in the third
Total of 13 units.
row*cols + col gives you 2*5 + 3 ie. 13
So if you move row*cols + col units from origin, you get to your current location.
The reality is that the 2-D grid you're imagining is actually represented as contiguous, linear memory.
So to access a coordinate at index (r,c) you need to start at the base address of the array, then skip to the r-th row by multiplying the row index (r) by the number of columns in each row--again, we're moving in a linear direction. This will bring you to the first column of the r-th row. From here you increment the pointer by c columns and you're at your destination.
So in your code, I'm assuming original is the start of your array. Therefore the line:
original + row*cols + col
is doing exactly what I described above.
row-column coordinates tend to lead to some confusion when mixed with something different... for example with the typical image coordinate system, where the origin is the top-left corner.
a matrix has coordinates indicated as (row, column). That's equivalent to (y,x) in the coordinates of the image: by incrementing rows you go down; incrementing columns, right.
In your code the 2D space, is just following the typical convention of both C (row-major) and of images (by lines). So you can read:
SOMETHING* o = original + row*cols + col;
as
SOMETHING* o = original + iy*width + ix;
note finally that this is the same of using static 2D arrys in C, so these would be equivalent:
original[NROWS][NCOLS];
...
SOMETHING *o = &original[row][col];
or
SOMETHING original[HEIGHT][WIDTH];
...
SOMETHING *o = &original[iy][ix];
with the very important limitation that in this case the dimensions must be known at compile time. In your case you are dealing with dynamic bidimensional arrays, that are not supported by the C language.
To conclude, being SOMETHING a pixel, let me guess...
struct SOMETHING {
unsigned char r;
unsigned char g;
unsigned char b;
};
it means that any element addressed in one of the two ways is just 3 bytes long, and they are just arranged contiguous.

two dimensional Arrays access using pointers

Is
*(ary[3]+8)
and
ary[3][8]
are the same ? If yes, please explain how ? ary[3] returns the address of first element or the value in ary[3][0] ? ary is a two dimensional array.
Thanks in advance.
Yes
a[i] is same as *(a+i)
ary[i][j] is same as *( *(ary+i)+j))
If x is an array (int, say) x[i] is just a syntactic sugar for *(x+i). In your case, ary is a two-dimensional array (again of int, say). By the same syntactic sugar mechanism, ary[i][j] is equivalent to *((*(ary+i))+j), from which it is clear what happens under the hood.
*(ary[3]+8) says value at 8th column of third row.ary[3] is base address of third Row.ary[3][8] will also access to same element at third row and 8th column.
For Example i am taking an 2D array of two row and 4 column which is equivalent to 1D array of 8 elements.As shown below.
int a[8] = {0,1,2,3,4,5,6,7};
int b[2][4] = {{0,1,2,3},{4,5,6,7}};
since b is 2D array , so you can consider it as array of two 1D arrays.when you pass b[1] or b[1][0] it says address of first row.Rectangular array allocated in memory by Row.so if you want to find address of element a[row][col] it will get calculated as
address = baseAddress + elementSize * (row*(total number of column) + col);
As others already have said, a[i] is just a sugar for *(a+i).
I just would like to add that it always works, that allows us to do things like that:
char a[10];
char b;
char c[10][20];
// all of these are the same:
b = a[5]; // classic
b = *(a + 5); // pointer shifting
b = 5[a]; // even so!
b = c[5][9];
b = *(c[5] + 9);
b = *(*(c + 5) + 9);
b = *(c + 5)[9];
b = 5[c][9];
b = 5[9][c]; // WRONG! Compiling error

Resources