Indexing multidimensional arrays in C - 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.

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.

Multi-dimensional array access using pointer in 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.

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

C extract an array from a matrix using pointers

I wrote a code and I have some data stored in a 2d matrix:
double y[LENGTH][2];
I have a function that take as input a 1D array:
double function(double* data)
I am interested in passing the data stored in the first column of this matrix to this function. How can I do that using pointers?
My function is something like (where the array data is an array of double containing LENGTH elements:
double data[LENGTH];
):
double function(double* data){
double result=0;
for(int i=0; i<LENGTH; i++){
result+=data[i];
}
return result;
}
And I want to pass to this function a row of a matrix as data input.
Thanks to everyone in advance!
If you pass a pointer to the first element of your 2D matrix, you can access it as a 1 D matrix since the elements are stored contiguously:
double y[LENGTH][2];
x = function(y[0]);
...
double function(double* p) {
int ii;
double sum=0;
for(ii=0; ii<2*LENGTH; ii++) sum += p[ii];
return sum;
}
Note that in this case the order of accessing the elements is
y[0][0]
y[0][1]
y[1][0]
y[1][1]
y[2][0]
... etc
update - you just clarified your question a little bit. If you want to access just one column of data, you need to skip through the array. This means you need to know the size of the second dimension. I would recommend something like this:
double function(double* p, int D2) {
int ii;
double sum=0;
for(ii=0; ii<D2*LENGTH; ii+=D2) sum += p[ii];
return sum;
}
And you would call it with
x = function(y[colNum], numCols);
Now we start at a certain location, then, skip forward D2 elements to access the next element in the column.
I have to say that this is rather ugly - this is not really how C is intended to be used. I would recommend wrapping things into a class that handles these things for you cleanly - in other words, switch to C++ (although it's possible to write pure C functions that "hide" some of this complexity). You could of course copy the data to another memory block to make it contiguous, but that's usually considered a last recourse.
Be careful that you don't end up with code that is unreadable / unmaintainable...
further update
Per your comment, the above is still not what you wanted. Then I recommend the following:
double *colPointer(double *p, int rowCount, int colCount) {
double *cp;
int ii;
cp = malloc(rowCount * sizeof *cp);
for(ii=0; ii<rowCount; ii++) cp[ii] = *(p + ii * colCount);
return cp;
}
This will return a pointer to a newly created copy of the column. You call it with
double *cc;
cc = colPointer(y[colNum], LENGTH, 2);
answer = function(cc);
And now you can use cc in the way you wanted. If you have to do this many times you might be better off transposing the entire array just once - that way you can pass a pointer to a row of the transpose and achieve your result. You can adapt the code above to generate such a transpose.
Note that there is a risk of memory leaks if you don't clean up after yourself with this method.
the question is that do you consider to be the row-dimension.
usually the first one is rows and the second one cols.
that means that your double y[LENGTH][2]; is a matrix with LENGTH rows ans 2 cols.
if that is also your interpretation then the answer to your question is "you can't" since the memory is layed out like this:
r0c0 r0c1 r1c0 r1c1 r2c0 r2c1 ...
you can retrieve pointer to a row but not to a column.
matrix classes are usually designed in a way, that row and column step length is stored so that by carefully setting them you can build sub matrices on a big data chunk.
you may look for opencv matrix implementation if you plan to perform complexer tasks.
if you can change the implementation of the function you want to call. you can change it to accept the row step (number of your columns), so that it does not joust increment the pointer by one to reach the next element but to increment the pointer by row step.
as an alternative there is the obvious way to copy the required column to a new array.
edit:
fixed stupid error on memory layout diagram

Delete a column from a double array

I'm stuck here. I've got a matrix of size NxN stored in a double array. Then I want to delete a given column, lets say the first column. So I created a new double array of size NxN-1 and copy the values from the first matrix to the second one, except the 1st column of course. But then I want to set the first array to be the second array. I am blanking here.
double matrix[N][N]
//fill up the matrix code here...
// remove first column of array
double newMatrix[N][N-1];
for(i = 0; i < N; i++){
for(j = 1; j < N; j++){
newMatrix[i][j-1] = matrix[i][j];
}
}
matrix = newMatrix; // how do I set this correctly? Do I need to realloc the first array?
You cannot assign arrays in C, which I assume that your compiler tells you. To do such dynamic memory management, you will need to use pointers instead of arrays. I suggest you read up on how malloc() and free() work so that you can do what you want.
Edit:
Another solution comes to mind if you are only removing columns (or rows): keep track of the number of rows and columns used in the array. Then you can remove a row or column within the original array without creating a copy first. Just move the data past the delete column (or row) to the left (or up) then decrement your size counters. (I hope this make sense. If not let me know and I'll elaborate.)
like Code-guru said malloc() and free() should help alot, but if u simply wanted to delete the last column the you wouldn't need two arrays:
double matrix[2][3] = {1,2,3,4,5,6}; //declaring a 2 by 3 matrix
for (i=0;i<2;i++) //rows
{
for (j=0;j<3-1;j++) //columns - 1
{
printf("%.1f ",matrix[i][j]); //I chose to display matrix...
}
printf("\n");
}
Instead of accessing elements from array[i][j], one might opt to access elements from array + stride_x[x] + stride_y[y]; where array is originally introduced as double matrix[N*N]; or double *matrix = malloc(sizeof(double)*N*N);.
The stride_y[x] would originally contain offsets of columns for all rows: 0 1 2 3 4 ... N-1 and stride_y[y] would contain similar offsets multiplied with original row width 0 N 2*N 3*N..
From these 1-D arrays one can more effortlessly delete or exchange complete rows and columns, which may come handy in eg. recursive implementation of determinant calculation / Gauss Jordan elimination.

Resources