-
Notifications
You must be signed in to change notification settings - Fork 0
section8_arrays_functions
In this page we will cover how to pass arrays to functions. We will explore two notations and highlight some problems.
When passing arrays to functions, instead of directly working with the array you are working with pointers (yes, a true pointer).
void foo(int array[]) {
/* ... */
}
int main() {
int a[10];
foo(a);
}
In the example above, an array of integers, with 10 elements, is declared, a
.
When you call the function foo
, it expects an array as the first parameter. Thus, the variable a
is passed. Recall that in C arguments are passed by value, i.e, they are copies. In the case of arrays, a new pointer to integers, let's call it _ptr
, is initialized with the same address as a
. Therefore, you can access the array a
inside the function through a new pointer.
The first problem to be addressed is how to know the size of the array. Recall from previous sections that you can only apply the sizeof
operator directly on the array variable. It won't work with pointers that refer to the array's first element.
The workaround for this is passing the size of the array through an argument. Or, in more simple cases, use a global constant variable or a macro.
int sum(int array[], unsigned int size) {
int sum = 0, i;
for(i = 0; i < size; i++) {
sum += array[i];
}
return sum;
}
int main() {
int a[10] = {1, 3, 4, -1, -3, -4};
printf("Sum: %d\n", sum(a, 10));
}
C is meant to be efficient. And some times the focus on efficiency makes the life of developers harder. When you pass an array to a function, instead of creating a copy of the array, which is expensive in CPU time and might use extra memory without need, you get a pointer to the original array. Therefore, any changes to the array inside the function, affect the original array.
The solution for the problem is to use functions for creating a copy of that array. Two possible functions to achieve the goal are memcpy
and strncpy
.
Below is an illustration of the memcpy
function. You must the preprocessor directive #include <string.h>
.
The prototype for this function is:
void *memcpy(void *dest, const void *src, size_t n);
The dest
is the destination for the copy, the src
is the original content, and n
is the amount of bytes to copy. Notice is not the number of elements, but the number of bytes.
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int copy[10];
memcpy(copy, a, 10*sizeof(int));
/* multiply all values in copy, same as 'a', by 5 */
int i;
for(i = 0; i < 10; i++) {
copy[i] = a[i]*5;
}
/* print both array values */
for(i = 0; i < 10; i++) {
printf("a[%d]: %d \t copy[%d]: %d\n", i, a[i], i, copy[i]);
}
The output is:
a[0]: 1 copy[0]: 5
a[1]: 2 copy[1]: 10
a[2]: 3 copy[2]: 15
a[3]: 4 copy[3]: 20
a[4]: 5 copy[4]: 25
a[5]: 6 copy[5]: 30
a[6]: 7 copy[6]: 35
a[7]: 8 copy[7]: 40
a[8]: 9 copy[8]: 45
a[9]: 10 copy[9]: 50
A good practice in C is to explicitly say that a function won't change the passed parameter. This let's you know wether the function will change or not the array you are passing. If it changes and you want to preserve the original content, then your only hope is to copy. When you declare a parameter as const
, if inside the funciton you attempt to change the variable the compiler will throw an error.
int foo(const int array[], int size) {
array[0] = 100;
return 0;
}
int main() {
int a[10];
foo(a, 10);
}
It will produce the following error:
demo.c: In function ‘foo’:
demo.c:3:11: error: assignment of read-only location ‘*array’
array[0] = 100;
^
In our function prototypes we have used the array notation. However, it's a bit misleading, because as we said, it's not really an array variable, instead is a true pointer. Therefore the following notation is prefered:
int foo(int *array, unsigned int size) {
/* ... */
}
Soon...