Reputation: 29084
I have a 2-dimensional array and I am passing it into a function to carry out certain operations. I'd like to know the correct way of doing it...
#define numRows 3
#define numCols 7
#define TotalNum (numRows*numCols)
int arr[numRows][numCols] = {{0,1,2,3,4,5,6}, {7,8,9,10,11,12,13},{14,15,16,17,18,19,20}};
void display(int **p)
{
printf("\n");
for (int i = 0; i< numRows;i++)
{
for ( int j = 0;j< numCols;j++)
{
printf("%i\t",p[i][j]);
}
printf("\n");
}
}
int main() {
display(arr);
}
I get an error message:
'display': cannot convert parameter1 from 'int' to 'int*'
Is this the correct way of passing a 2-dimensional array into a function? If not, what is the correct way?
Upvotes: 55
Views: 148328
Reputation: 1206
You are doing in wrong way. You can pass 2-d array with the help of pointer to an array, or simply pass an array or through Single pointer.
#define numRows 3
#define numCols 7
void display(int (*p)[numcols],int numRows,int numCols)//First method//
void display(int *p,int numRows,int numCols) //Second Method//
void display(int numRows,int numCols,int p[][numCols]) //Third Method
{
printf("\n");
for (int i = 0; i < numRows;i++)
{
for ( int j = 0; j < numCols;j++)
{
printf("%i\t",p[i][j]);
}
printf("\n");
}
}
int main() {
display(arr,numRows,numCols);
}
Upvotes: 6
Reputation: 4280
You can change the signature of display method as follows:
void display(int (*p)[numCols])
Here, p
is a pointer to the row of a 2D array. The pointer only needs to know the number of columns in the array.
Actually speaking, pointer need to know the size of each row. This is very important for pointer arithmetic. So that when you increment the pointer, the pointer must point to next row.
Note here, p
is not a normal integer pointer. It's a integer pointer to the memory size equal to integer_size x columns
.
In main you don't need to change anything. display(arr)
is just fine.
Upvotes: 0
Reputation: 5970
There are several, sometimes equivalent ways of doing this. By declaring an array (cf. method_c()
), by using a pointer (cf. method_b()
) or by using a pointer to an array of an array (cf. method_a()
). method_b()
, using a single pointer, is slightly more difficult to get right since it is not easy to use standard array indexing and hence, we use pointer arithmetic. method_a()
and method_c()
are basically equivalent since arrays decay non-recursively to pointers during compilation. Here is a little program illustrating all three methods. We first initialize a 2x4
-array arr
in a simple for loop and print it. It will look like this:
arr:
0 1 2 3
0 1 2 3
Afterwards we call all three methods. method_a()
adds 1, method_b()
adds 2 and method_c()
adds 3 to all elements. After each call we print out the array arr
again. If a function worked correctly you will easily see it on the output. Size is arbitrary and can be regulated via the two macros ROW
and COL
. One last note, method_c()
relies on variable-length array present since C99
.
#include <stdio.h>
#include <stdlib.h>
#define ROW 2
#define COL 4
void method_a(int m, int n, int (*ptr_arr)[n]);
void method_b(int m, int n, int *ptr_arr);
void method_c(int m, int n, int arr[][n]);
int main(int argc, char *argv[]) {
int arr[ROW][COL];
int i;
int j;
for(i = 0; i < ROW; i++) {
for(j = 0; j < COL; j++) {
arr[i][j] = j;
}
}
printf("Original array:\n");
for (i = 0; i < ROW; i++) {
for(j = 0; j < COL; j++) {
printf("%d\t", arr[i][j]);
}
printf("\n");
}
printf("\n\n");
method_a(ROW, COL, arr);
printf("method_a() array:\n");
for (i = 0; i < ROW; i++) {
for(j = 0; j < COL; j++) {
printf("%d\t", arr[i][j]);
}
printf("\n");
}
printf("\n\n");
printf("method_b() array:\n");
method_b(ROW, COL, (int *)arr);
for (i = 0; i < ROW; i++) {
for(j = 0; j < COL; j++) {
printf("%d\t", arr[i][j]);
}
printf("\n");
}
printf("\n\n");
method_c(ROW, COL, arr);
printf("method_c() array:\n");
for (i = 0; i < ROW; i++) {
for(j = 0; j < COL; j++) {
printf("%d\t", arr[i][j]);
}
printf("\n");
}
printf("\n\n");
return EXIT_SUCCESS;
}
void method_a(int m, int n, int (*ptr_arr)[n])
{
int i, j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
ptr_arr[i][j] = j + 1;
}
}
}
void method_b(int m, int n, int *ptr_arr)
{
int i, j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
/* We need to use pointer arithmetic when indexing. */
*((ptr_arr + i * n) + j) = j + 2;
}
}
/* The whole function could have also been defined a bit different by taking
* the i index out of the pointer arithmetic. n alone will then provide our
* correct offset to the right. This may be a bit easier to understand. Our
* for-loop would then look like this:
* for (i = 0; i < m; i++)
* {
* for (j = 0; j < n; j++)
* {
* *((ptr_arr + n) + j) = j + 2;
* }
* ptr_arr++;
* }*/
}
void method_c(int m, int n, int arr[][n])
{
int i, j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
arr[i][j] = j + 3;
}
}
}
Upvotes: 6
Reputation: 11841
Declare it simply
void display(int (*p)[numCols][numRows]);
This way your p
pointer conveys all necessary informations and you can extract all the dimensions from it without repeating numCols
and numRows
over and over.
void display(int (*p)[numCols][numRows])
{
size_t i, j;
printf("sizeof array=%zu\n", sizeof *p);
printf("sizeof array[]=%zu\n", sizeof **p);
printf("sizeof array[][]=%zu\n", sizeof ***p);
size_t dim_y = sizeof *p / sizeof **p;
printf("dim_y = %zu\n", dim_y);
size_t dim_x = sizeof **p / sizeof ***p;
printf("dim_x = %zu\n", dim_x);
for(i=0; i<dim_y; i++) {
puts("");
for(j=0; j<dim_x; j++)
printf(" %6d", (*p)[i][j]);
}
}
This is particularly interesting if you use typedefs (which I don't like btw)
typedef int matrix[5][6];
In that case the dimensions are not visible in the signature of the function but the function will still have the correct values for the dimensions.
Upvotes: 0
Reputation: 5456
If (like in your case), you know the dimensions of the array at compilation-time, you can write justvoid display(int p[][numCols])
.
Some explanation: You probably know that when you pass an array to a function, you actually pass a pointer to the first member. In C language, 2D array is just an array of arrays. Because of that, you should pass the function a pointer to the first sub-array in the 2D array. So, the natural way, is to say int (*p)[numCols]
(that means p is a pointer, to an array of numCols
ints). In function declaration, you have the "shortcut" p[]
, that means exactly the same thing like (*p)
(But tells the reader, that you pass a pointer to a beginning of array, and not to just an one variable)
Upvotes: 13
Reputation: 182664
You should declare your function like this:
void display(int p[][numCols])
This C FAQ thoroughly explains why. The gist of it is that arrays decay into pointers once, it doesn't happen recursively. An array of arrays decays into a pointer to an array, not into a pointer to a pointer.
Upvotes: 72