Generally when we pass array by its name, it’s call by address. That means if we change any value of array outside main()
it will be reflected in main()
.
So, what should I do to if I want to pass the array as an argument of a function and call it inside main()
such that any change in that function won't be reflected inside main()
?
For example:
void Foo(int arr[]) //takes an integer array `arr` as argument
{
// do something with `arr
}
int main()
{
int abc[]={5,1,2,9};
//do something to pass `abc` inside `Foo` so that changes inside `Foo` doesn't change the value of `abc` array.
}
Now I want to pass the abc
array to Foo
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 100
struct 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 20
Original
1 2 3 4 5 6 7 8 9 10
Transformed
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With