I am currently attempting to create a triple pointer to point to and update the contents of a statically allocated 3d array in C. The updating of the elements of the array will be completed by a function like:
void effect_array(int ***ptr, int rows, int cols, int depth)
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
for(int k = 0; k < depth; k++)
{
ptr[i][j][k] *= 2;
}
}
}
}
In the build up to my attempt I was successful at doing the following for a 2d/double pointer:
#include <stdio.h>
#include <stdlib.h>
void effect_array2d(int **ptr, int rows, int cols)
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
ptr[i][j] *= 2;
}
}
}
int main()
{
int arr[2][2] = {
{1,2},
{3,4}
};
int **ptr = (int **)malloc(2 * sizeof(int *));
for(int i = 0; i < 2; i++) ptr[i] = arr[i];
printf("Array before pass to effect_array2d:\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
printf("\n");
effect_array2d(ptr, 2, 2);
printf("Array after pass to effect_array2d:\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
printf("\n");
free(ptr);
return 0;
}
which gives an output of:
Array before pass to effect_array2d:
1 2
3 4
Array after pass to effect_array2d:
2 4
6 8
However when I try to use the same method for a 3d array and triple pointer:
#include <stdio.h>
#include <stdlib.h>
void effect_array(int ***ptr, int rows, int cols, int depth)
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
for(int k = 0; k < depth; k++)
{
ptr[i][j][k] *= 2;
}
}
}
}
int main()
{
int arr[2][2][2] = {
{
{1,2},
{3,4}
},
{
{5,6},
{7,8}
}
};
int ***ptr = (int ***)malloc(2 * sizeof(int **));
for(int i = 0; i < 2; i++)
{
ptr[i] = arr[i];
}
free(ptr);
return 0;
}
I am met with a warning stating that:
malloc3.c: In function ‘main’:
malloc3.c:34:16: warning: assignment to ‘int **’ from incompatible pointer type ‘int (*)[2]’ [-Wincompatible-pointer-types]
34 | ptr[i] = arr[i];
| ^
Not sure how to get around this, or what I am doing wrong. Any and all help is greatly appreciated.
I am currently attempting to create a triple pointer to point to and update the contents of a statically allocated 3d array in C. The updating of the elements of the array will be completed by a function like:
void effect_array(int ***ptr, int rows, int cols, int depth)
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
for(int k = 0; k < depth; k++)
{
ptr[i][j][k] *= 2;
}
}
}
}
In the build up to my attempt I was successful at doing the following for a 2d/double pointer:
#include <stdio.h>
#include <stdlib.h>
void effect_array2d(int **ptr, int rows, int cols)
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
ptr[i][j] *= 2;
}
}
}
int main()
{
int arr[2][2] = {
{1,2},
{3,4}
};
int **ptr = (int **)malloc(2 * sizeof(int *));
for(int i = 0; i < 2; i++) ptr[i] = arr[i];
printf("Array before pass to effect_array2d:\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
printf("\n");
effect_array2d(ptr, 2, 2);
printf("Array after pass to effect_array2d:\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
printf("\n");
free(ptr);
return 0;
}
which gives an output of:
Array before pass to effect_array2d:
1 2
3 4
Array after pass to effect_array2d:
2 4
6 8
However when I try to use the same method for a 3d array and triple pointer:
#include <stdio.h>
#include <stdlib.h>
void effect_array(int ***ptr, int rows, int cols, int depth)
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
for(int k = 0; k < depth; k++)
{
ptr[i][j][k] *= 2;
}
}
}
}
int main()
{
int arr[2][2][2] = {
{
{1,2},
{3,4}
},
{
{5,6},
{7,8}
}
};
int ***ptr = (int ***)malloc(2 * sizeof(int **));
for(int i = 0; i < 2; i++)
{
ptr[i] = arr[i];
}
free(ptr);
return 0;
}
I am met with a warning stating that:
malloc3.c: In function ‘main’:
malloc3.c:34:16: warning: assignment to ‘int **’ from incompatible pointer type ‘int (*)[2]’ [-Wincompatible-pointer-types]
34 | ptr[i] = arr[i];
| ^
Not sure how to get around this, or what I am doing wrong. Any and all help is greatly appreciated.
Share Improve this question asked Feb 1 at 18:46 frankfrank 311 silver badge6 bronze badges 12 | Show 7 more comments3 Answers
Reset to default 2The problem is simply that pointers are not arrays. Arrays are not pointers. An array may "decay" into a pointer to the first element in some cases, but that only happens once. Only on the left-most dimension when you have a multi-dimensional array.
This means that while me may pass an int[x]
to a function expecting a int*
, we can't pass an int[x][y]
to a function expecting an int**
. And so on.
Simply write the function like this instead, and keep the function body as it is:
void effect_array(int rows, int cols, int depth, int arr[rows][cols][depth])
This is a variable-length array (VLA) which can be set to any dimension of a previously known variable, meaning it has to be declared on the right-hand side of any such variable. Here the 3D array is passed by reference, not by value as it might look like (you can't pass arrays by value in C).
Now if you pass a 3D array int [x][y][z]
to this function, then in the function calling expression that array will "decay" into a pointer to the first element. The first element is type int [y][z]
and so a pointer to that becomes int (*)[y][z]
.
Now as it happens, that same "decay" happens to the declared parameter int arr[rows][cols][depth]
too - it gets adjusted ("decays") into the type int (*arr)[cols][depth]
. And suddenly we got two compatible types so this will work just fine.
However this requires that you have a 3D array on the caller side too. Some int***
is not an array nor can it be used to point at a 3D array, so that's a useless declaration - and even if you get it to work, it is needlessly slow for no good reason because of heap fragmentation etc. Fet that you ever saw it. More info about how to allocate arrays correctly here: Correctly allocating multi-dimensional arrays
Instead we can declare a pointer to a 2D array and when we dereference that it will be as if using a 3D array:
int x = 2;
int y = 2;
int z = 2;
int (*ptr)[y][z] = malloc( sizeof(int[x][y][z]) );
A triple-pointer (i.e. int ***ptr
) is not what you need for this task. And that's what the warning tells you.
An important thing to know about C is what happens when you use an array variable. With a few exceptions (e.g. sizeof
), there is an implicit conversion to "a pointer to the first array element".
Example for simple array:
int arr[N];
int n = arr[0];
// Since arr[0] holds an int, a pointer to the first element of the array,
// will have the type "pointer to int", so we can do things like:
void foo(int* a) {....}
^^^^
int arr[N];
foo(arr);
int* p = arr;
^^^^
When moving to a 2D array, i.e. is an array of array of e.g. int, things get a little more complex:
int arr[M][N];
??? p = arr[0]; // What type shall p have ???
As arr
is an array of array of int, arr[0]
is an array of int, arr[1]
is an array of int, and so on. So one could think that this would be correct:
int arr[M][N];
int p[N] = arr[0]; // THIS IS WRONG !!!
But it's wrong! The implicit conversion for arrays means that the type will be a pointer to the first element of a[0]
. Since the first element of a[0]
(i.e. a[0][0]
) is an int, we end up with an int pointer. Like:
int arr[M][N];
int* p = arr[0]; // Correct
So let's move to the 3D case. The array of array of array of int. Note: int is just used as a simple example, it could be other types.
int arr[K][M][N];
??? p = arr[0]; // What type shall p have ???
Now things get a little complex but just apply the same way of thinking. Then we get: a[0]
is an "array of array of int" (2D). When using a[0]
the conversion rule says we end up with a pointer to the first element of that "array of array of int". The first element of the is "array of int" so we end up with "a pointer to an array of int". That looks like:
int arr[K][M][N];
int (*p)[N] = arr[0]; // Pointer to array of int with N elements
Now for your code... You don't want just a single of those pointers - you want an array. So you could do:
int (*ptr[2])[2]; // array of pointer to array of int
for(int i = 0; i < 2; i++)
{
ptr[i] = arr[i];
}
oh... you also wanted dynamic allocation. So you need:
int (**ptr)[2] = malloc(2* sizeof *ptr);
for(int i = 0; i < 2; i++)
{
ptr[i] = arr[i];
}
Then you also need to change the function so that the pointer has the correct type:
void effect_array(int (**ptr)[2], int rows, int cols, int depth)
{
...
}
That's it.
Example:
#include <stdio.h>
#include <stdlib.h>
#define ROWS 2
#define COLS 3
#define DEPTH 4
void effect_array(int (**ptr)[DEPTH], int rows, int cols, int depth)
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
for(int k = 0; k < depth; k++)
{
ptr[i][j][k] *= 2;
}
}
}
}
int main()
{
int arr[ROWS][COLS][DEPTH] = {
{
{1, 2, 11, 22},
{3, 4, 33, 44},
{100, 200, 300, 400}
},
{
{5,6},
{7,8}
}
};
int (**ptr)[DEPTH] = malloc(COLS * sizeof *ptr);
for(int i = 0; i < COLS; i++)
{
ptr[i] = arr[i];
}
effect_array(ptr, ROWS, COLS, DEPTH);
printf("Array after pass to effect_array2d:\n");
printf("{");
for(int i = 0; i < ROWS; i++)
{
printf("{");
for(int j = 0; j < COLS; j++)
{
printf("{");
for(int k = 0; k < DEPTH; k++)
{
printf("%d, ", arr[i][j][k]);
}
printf("}, ");
}
printf("}, ");
}
printf("}\n");
free(ptr);
return 0;
}
Output:
Array after pass to effect_array2d:
{{{2, 4, 22, 44, }, {6, 8, 66, 88, }, {200, 400, 600, 800, }, }, {{10, 12, 0, 0, }, {14, 16, 0, 0, }, {0, 0, 0, 0, }, }, }
I have seen this problem before, and it is a pretty tough one because C handles 3D arrays a little differently than it does the 2D ones. Here is what I did to solve the problem:
#include <stdio.h>
#include <stdlib.h>
void effect_array(int ***ptr, int rows, int cols, int depth)
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
for(int k = 0; k < depth; k++)
{
ptr[i][j][k] *= 2;
}
}
}
}
int main()
{
int arr[2][2][2] = {
{
{1, 2},
{3, 4}
},
{
{5, 6},
{7, 8}
}
};
// Allocate memory for rows
int ***ptr = (int ***)malloc(2 * sizeof(int **));
// Allocate memory for columns in each row
for(int i = 0; i < 2; i++)
{
ptr[i] = (int **)malloc(2 * sizeof(int *));
for(int j = 0; j < 2; j++)
{
// Point to the correct part of the original array
ptr[i][j] = &arr[i][j][0];
}
}
printf("Array before:\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
for(int k = 0; k < 2; k++)
{
printf("%d ", arr[i][j][k]);
}
printf("\n");
}
printf("\n");
}
effect_array(ptr, 2, 2, 2);
printf("Array after:\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
for(int k = 0; k < 2; k++)
{
printf("%d ", arr[i][j][k]);
}
printf("\n");
}
printf("\n");
}
for(int i = 0; i < 2; i++)
{
free(ptr[i]);
}
free(ptr);
return 0;
}
The difference of this program using 2D arrays is that you have to handle two levels of memory allocation. After declaration, for each row, you have to reallocate for each column. After this, you can point to elements of the original array. The warning you are seeing arises because arr[i] in a 3D array isn't the same type as what ptr[i] expects. In this solution, we allocate memory for both rows and columns and then point to the actual data. and don’t fet to free the memory in the correct order to avoid leaks.
***
. – Arkadiusz Drabczyk Commented Feb 1 at 18:53***
pointer. The solution is in the warning, i.e. use the type the warning tells you. – 4386427 Commented Feb 1 at 19:38int (**ptr)[2] = malloc(2 * sizeof *ptr);
and work from there – 4386427 Commented Feb 1 at 20:06