Passing a dynamically allocated array as a parameter in C

So ... I have a dynamically allocated array on my main:

int main() { int *array; int len; array = (int *) malloc(len * sizeof(int)); ... return EXIT_SUCCESS; } 

I also want to create a function that does something with this dynamically allocated array. So far, my function is:

 void myFunction(int array[], ...) { array[position] = value; } 

If I declare it as:

 void myFunction(int *array, ...); 

I can still do:

 array[position] = value; 

Or I will have to do:

 *array[position] = value; 

...

Also, if I work with a dynamically distributed matrix, which one is the right way to declare a function prototype:

 void myFunction(int matrix[][], ...); 

or

 void myFunction(int **matrix, ...); 

...

+4
source share
4 answers

If I declare it as:

 void myFunction(int *array, ...); 

I can still do:

 array[position] = value; 

Yes is legal syntax.

In addition, if I work with a dynamically distributed matrix, which function prototype should be declared correctly:

 void myFunction(int matrix[][], ...); 

or

 void myFunction(int **matrix, ...); 

...

If you work with multiple dimensions, you need to declare the size of everything except the first dimension in the function declaration, for example:

 void myFunction(int matrix[][100], ...); 

This syntax will not do what you think:

 void myFunction(int **matrix, ...); matrix[i][j] = ... 

This declares a parameter called matrix , which is a pointer to a pointer to an int; attempting dereferencing with matrix[i][j] is likely to cause a segmentation error.

This is one of the many challenges of working with a multidimensional array in C.

Here is a useful SO question dedicated to this topic: Define a matrix and pass its functions to C

+6
source

I can still do:

 array[position] = value; 

Yes, since the index operator p[i] is 100% identical to *(ptr + i) . In fact, you can write 5[array] instead of array[5] , and it will still work. C arrays are actually just pointers. The only thing that makes the definition of the array different from the pointer is that if you take the sizeof the array identifier “true”, it gives you the actual storage size, and when using the sizeof pointer, you just specify the size of the pointer, which is usually a system integer size (may be different).

Also, if I work with a dynamically distributed matrix, which one is the right way to declare a function prototype: (...)

None of them, since they are arrays of pointers to arrays that may be incoherent. For performance reasons, you want matrices to be contiguous. Therefore you just write

 void foo(int matrix[]) 

and internally calculate the correct offset, for example

 matrix[width*j + i] 

Note that writing this using parenthesis syntax looks weird. Also note that if you take the sizeof pointer or function parameter "array of unspecified length", you will get the size of the pointer.

+1
source

No, you just keep using array[position] = value .

After all, there is no real difference whether you declare an int *something or int something[] parameter. Both will work because the definition of an array is just hidden pointer math.

However, there is one difference in how you understand the code:

  • int array[] always denotes an array (it can only be one element long, though).
  • int *pointer however can be a pointer to a single integer or a whole array of integers.

Regarding addressing / presentation: pointer == array == &array[0]

If you work with multiple dimensions, everything is a little different, because C forces you to declare the last dimension if you explicitly define multidimensional arrays:

 int **myStuff1; // valid int *myStuff2[]; // valid int myStuff3[][]; // invalid int myStuff4[][5]; // valid 
+1
source

Yes, use array[position] , even if the parameter type is int *array . The alternative you gave ( *array[position] ) is actually invalid in this case, because the [] operator takes precedence over the * operator, which makes it equivalent to *(array[position]) , which is trying to dereference the value of a[position] , but not this address.

It gets a little more complicated for multidimensional arrays, but you can do this:

 int m = 10, n = 5; int matrixOnStack[m][n]; matrixOnStack[0][0] = 0; // OK matrixOnStack[m-1][n-1] = 0; // OK // matrixOnStack[10][5] = 0; // Not OK. Compiler may not complain // but nearby data structures might. int (*matrixInHeap)[n] = malloc(sizeof(int[m][n])); matrixInHeap[0][0] = 0; // OK matrixInHeap[m-1][n-1] = 0; // OK // matrixInHeap[10][5] = 0; // Not OK. coloring outside the lines again. 

The way to interpret the matrixInHeap is that the "thing" that matrixInHeap points to is an array of n int values, so sizeof(*matrixInHeap) == n * sizeof(int) or the size of the entire row in the matrix. matrixInHeap[2][4] works because matrixInHeap[2] advances the matrixInHeap address by 2 * sizeof(*matrixInHeap) , which skips two full lines of integers n , which leads to the address of the third row, and then selects the final [4] the fifth element from the third row. (remember that array indices start at 0, not 1)

You can use the same type when pointing to regular multidimensional c-arrays (if you already know the size):

 int (*matrixPointer)[n] = matrixOnStack || matrixInHeap; 

Now let's say that you want to have a function that takes one of these variable sized matrices as a parameter. When the variables were declared earlier, the type had some size information (both dimensions in the stack example and the last dimension n in the heap example). Thus, the type of the parameter in the definition of the function will need the value of n , which we can really do if we include it as a separate parameter, defining such a function:

 void fillWithZeros(int m, int n, int (*matrix)[n]) { for (int i = 0; i < m; ++i) for (int j = 0; j < n; ++j) matrix[i][j] = 0; } 

If we do not need the value of m inside the function, we could leave it completely until we save n :

 bool isZeroAtLocation(int n, int (*matrix)[n], int i, int j) { return matrix[i][j] == 0; } 

And then we just include the size when calling the functions:

 fillWithZeros(m, n, matrixPointer); assert(isZeroAtLocation(n, matrixPointer, 0, 0)); 

This may seem a little like what we are working on compilers, especially in cases where we do not use n at all inside the function body (or only as a parameter for similar functions), but at least it works.

The final readability issue: using malloc(sizeof(int[len])) equivalent to malloc(len * sizeof(int)) (and anyone who tells you otherwise doesn't understand the layout of the structure in c), but the first way writing it makes it obvious to the reader that we are talking about an array. The same applies to malloc(sizeof(int[m][n])) and malloc(m * n * sizeof(int)) .

+1
source

Source: https://habr.com/ru/post/1499714/


All Articles