Pass an array by value
It is possible to do this by wrapping the array in a struct
. You can include a field for the size of the array so that you don't need to pass this parameter explicitly. This approach has the virtue of avoiding extra memory allocations that must later be freed.
C already passes arguments to functions by value, but array identifiers decay to pointers in most expressions, and in function calls in particular. Yet struct
s do not decay to pointers, and are passed by value to a function, meaning that a copy of the original structure and all of its contents is visible in the scope of the function. If the struct
contains an array, this is copied too. Note that if instead the struct
contains, say, a pointer to int
for a dynamic array, then the pointer is copied when the struct
is passed to the function, but the same memory is referenced by both the copy and the original pointer. This approach relies on the struct
containing an actual array.
Also note that a struct
can not contain a member with an incomplete type, and so can not contain a VLA. Here I have defined the global constant MAX_ARR
to be 100 to provide some space for handling differently sized arrays with the same struct
type.
You can also return a struct
from a function. I have included an example which modifies the Array
struct
which is passed into a function, and returns the modified struct
to be assigned to a different Array
struct
in the calling function. This results in the caller having access to both the original and the transformed arrays.
#include <stdio.h>#define MAX_ARR 100struct Array { size_t size; int array[MAX_ARR];};void print_array(struct Array local_arr);void func(struct Array local_arr);struct Array triple(struct Array local_arr);int main(void){ struct Array data = { .size = 10, .array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } }; struct Array transformed_data; func(data); transformed_data = triple(data); printf("Original\n"); print_array(data); printf("Transformed\n"); print_array(transformed_data); return 0;}void print_array(struct Array local_arr){ for (size_t i = 0; i < local_arr.size; i++) { printf("%5d", local_arr.array[i]); } putchar('\n');}void func(struct Array local_arr){ for (size_t i = 0; i < local_arr.size; i++) { local_arr.array[i] *= 2; } printf("Modified\n"); print_array(local_arr);}struct Array triple(struct Array local_arr){ for (size_t i = 0; i < local_arr.size; i++) { local_arr.array[i] *= 3; } return local_arr;}
Program output:
Modified 2 4 6 8 10 12 14 16 18 20Original 1 2 3 4 5 6 7 8 9 10Transformed 3 6 9 12 15 18 21 24 27 30
In general, you can't.
The caller can do something like this;
int main(){ int abc[]={5,1,2,9}; { int temp[sizeof (abc)/sizeof (*abc)]; memcpy(temp, abc, sizeof(abc)); Foo(temp); }}
Bear in mind that Foo()
does not receive any information about the number of elements in the array passed.
If you want Foo()
to do a similar thing, so the caller doesn't need to, it is necessary to pass the number of elements as a separate argument.
void Foo(int arr[], size_t size) /* C99 or later */{ int temp[size]; // VLA memcpy(temp, arr, size*sizeof(int)); /* whatever */}
or (before C99).
void Foo(int arr[], size_t size) /* Before C99 */{ int *temp = malloc(size * sizeof (int)); memcpy(temp, arr, size*sizeof(int)); /* whatever */ free(temp);}
To avoid a memory leak, it is necessary to ensure, in the second case, that the function does not return before calling free(temp)
.
In both versions of Foo()
above, additional error checking may be needed (e.g. to detect null pointer or zero sizes being passed, that malloc()
succeeds, etc).
(I am not sure why Ryan didn't volunteer to provide his own answer, but I agree that the following should work:)
#include <stdlib.h> // In header#include <string.h>int Foo(size_t size, int arr[]){ // guard against bad arguments if (arr == NULL || size <= 0) { return -1; } // create local array, since size is variable, allocate dynamically int* arr_2 = NULL; if ((arr_2 = malloc(n * sizeof(*arr_2)) == NULL) { return -1; // malloc allocation error } // otherwise if the size is constant: // int arr_2[SOME_CONSTANT_SIZE]; // copy from arr to arr_2 memcpy(arr_2, arr, n * sizeof(*arr_2)); // some computation free(arr_2); return 0;}
Remember that arr_2
will no longer exist once we leave the scope of Foo
. Also, for non-primitive array elements you would need to do more copying work.