Pass an array by value Pass an array by value arrays arrays

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 structs 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.