Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the exact differences betwenn int **a and int a[][] as function parameters in C and C++?

I have encountered this while writing a program with matrices, I used int** m to declare my matrix - because I needed dynamic allocation and in the function i used int a[][]. I don't remember having any problem with that. But when I used a simple m[6][6] matrix and f(int**m, int** m2, rest params) I had trouble.

It compiled and when I was running the program (code blocks with GCC) it just crashed. I tried debugging by adding printf()s and it was crashing at an if() block where it made no sense to crash. Modified the first function parameter from int a[][] to int* a[6] and it moved on, modified the second param later and my program worked on first try. By a more careful debug what I was saving in int m[i][j] and checking in the if was junk value, not what I was putting in, I was just putting 1 or 0 to mark something.

After all this years, unless I get compiler error by GCC when I do stuff like this, I just write the first way that comes to mind.

What is the logic behind using int** and int [][] to declare variable/get function parameters, in all 4 combinations? Most predefined functions I worked with use int** in the function header.

I know int [][] is not equivalent to int**, it is int* [] correctly, but what are the things that i'm missing? int[][] is an multi dimensional array means array of arrays, all 3 ways of writing it seem the same. And for int[][] it almost always asks to only let the first parameter void, like for int array[][][][] I need to put int array a[][n1][n2][n3] in the function parameter, right? It needs to know the dimension for multi-dimensional arrays except for the first one, because int* and int[] can be used without problems when declaring function arguments?

like image 668
Mihnea Avatar asked Nov 28 '22 19:11

Mihnea


2 Answers

What are the exact differences betwenn int **a and int a[][] as function parameters in C and C++?

int *a. This is a pointer to an int.

int **a. This is a pointer to pointer to an int.

int a[] This would be an array of unspecified number of ints in all other contexts, but as a function parameter declarator, it is adjusted to be a pointer to int i.e. in that case it is same as if you had written int *a.

int a[][] This would be an array of unspecified number of arrays of unspecified number of ints, but such type is ill-formed because the array element cannot be an array of unspecified size.

int *a[] This would be an array of unspecified number of pointers to int in all other contexts, but as a function parameter declarator, it is adjusted to be a pointer to pointer to int i.e. in that case it is same as if you had written int **a.

int (*a)[N] This is a pointer to an array of N ints.

int a[][N] This would be an array of unspecified number of arrays of N ints in all other contexts, but as a function parameter declarator, it is adjusted to be a pointer to an array of N int i.e. in that case it is same as if you had written int (*a)[N].


Some examples:

void fun_1D(int*);        // argument is pointer to int
void fun_1D(int[]);       // same as above
void fun_1D(int[10]);     // same as above; note that 10 is ignored

int arr_1D[20];           // array of int
fun_1D(arr_1D);           // implicit conversion
fun_1D(&arr_1D[0]);       // same as above

void fun_2D(int (*)[20]); // note that 20 is not ignored
void fun_2D(int[][20]);   // same as above
void fun_2D(int[10][20]); // same as above; note that 10 is ignored

int arr_2D[20][20];       // array of array of int
fun_2D(arr_2D);           // implicit conversion
fun_2D(&arr_2D[0]);       // same as above

fun_1D(arr_2D[i]);        // implicit conversion
fun_1D(&arr_2D[i][0]);    // same as above

void fun_ptrs(int**);     // argument is pointer to pointer to int
void fun_ptrs(int*[]);    // same as above
void fun_ptrs(int*[10]);  // same as above; note that 10 is ignored

int *arr_ptr[20];         // array of pointers
fun_ptrs(arr_ptr);        // implicit conversion
fun_ptrs(&arr_ptr[0]);    // same as above

fun_1D(arr_ptr[i]);       // no conversion needed


// broken examples
fun_2D(arr_ptr);          // int*[20] is not int(*)[20]
fun_ptrs(arr_2D);         // int[20][20] is not int**

Notice how a function parameter declared as an array is adjusted as the same pointer type to which an array will decay to upon lvalue to rvalue conversion.

Some simple rules of thumb to remember:

  • An array is not a pointer.
  • A pointer is not an array.
  • A function argument written as an array is actually not an array. It is actually adjusted to be a pointer to the element of such array. After this adjustement, a function argument is never an array. This does not apply to any other contexts, except for function arguments.
  • Not every type can be element of an array. Arrays of unspecified length are such types.
  • There are no objects of "array unspecified length" types. They can only be used in extern variable declarations which refer to an array defined elsewhere, or in a definition where the actual size is deduced from the initialiser of the array, or in a function parameter declaration where the array is adjusted to be a pointer to the element.

If I declare int a[6][6] in main and call a function that expects int** a, will it workd?

No, because int[6][6] is not an int** and neither does it decay to one. int[6][6] decays to int(*)[6] as I explained above. int(*)[6] and int** are not convertible to one another. One is pointer to an array, the other is pointer to a pointer.

And the other way around

No, because int[6][6] argument is adjusted to int(*)[6]. See previous paragraph for reason why these are incompatible.

seems int a[][] is not accepted

Correct. As I explained in the fourth paragraph from the top (not counting the quote).

If I have functions f1(int *a) and f2(int a[]) and f2(int a[6]) what would sizeof (a) return in those cases ?

As I explained above, all of those declare a parameter of type int*. sizeof a would be same as sizeof(int*) because that is the type.

like image 189
eerorika Avatar answered Dec 05 '22 10:12

eerorika


int **a

This is pointer to pointer to int.

int a[][]

This is array of array of int but this is not valid because the dimension of the second array must be known at declaration time, i.e. the second array must be complete, as it cannot be completed afterwards, like that

int a[][DIM]
like image 34
alinsoar Avatar answered Dec 05 '22 09:12

alinsoar