Clash Royale CLAN TAG#URR8PPP
Passing an array as an argument to a function in C
I wrote a function containing array as argument,
and call it by passing value of array as follows.
void arraytest(int a)
{
// changed the array a
a[0]=a[0]+a[1];
a[1]=a[0]-a[1];
a[0]=a[0]-a[1];
}
void main()
{
int arr={1,2};
printf("%d t %d",arr[0],arr[1]);
arraytest(arr);
printf("n After calling fun arr contains: %dt %d",arr[0],arr[1]);
}
What I found is though I am calling arraytest()
function by passing values, the original copy of int arr
is changed.
arraytest()
int arr
Can you please explain why?
9 Answers
9
When passing an array as a parameter, this
void arraytest(int a)
means exactly the same as
void arraytest(int *a)
so you are modifying the values in main.
For historical reasons, arrays are not first class citizens and cannot be passed by value.
struct
You are not passing the array as copy. It is only a pointer pointing to the adress where the first element is in memory.
You are passing the address of the first element of the array
In C, except for a few special cases, an array reference always "decays" to a pointer to the first element of the array. Therefore, it isn't possible to pass an array "by value". An array in a function call will be passed to the function as a pointer, which is analogous to passing the array by reference.
EDIT: There are three such special cases where an array does not decay to a pointer to it's first element:
sizeof a
sizeof (&a[0])
&a
&(&a[0])
&a[0]
char b = "foo"
char b = &("foo")
int a[10]
int y
int y[10]
int *y
sizeof(y)
sizeof
sizeof
You are passing the value of the memory location of the first member of the array.
Therefore when you start modifying the array inside the function, you are modifying the original array.
Remember that a[1]
is *(a+1)
.
a[1]
*(a+1)
If you want to pass a single-dimension array as an argument in a function, you would have to declare a formal parameter in one of following three ways and all three declaration methods produce similar results because each tells the compiler that an integer pointer is going to be received.
int func(int arr, ...){
.
.
.
}
int func(int arr[SIZE], ...){
.
.
.
}
int func(int* arr, ...){
.
.
.
}
So, you are modifying the original values.
Thanks !!!
Arrays in C are converted, in most of the cases, to a pointer to the first element of the array itself. And more in detail arrays passed into functions are always converted into pointers.
Here a quote from K&R2nd:
When an array name is passed to a function, what is passed is the
location of the initial element. Within the called function, this
argument is a local variable, and so an array name parameter is a
pointer, that is, a variable containing an address.
Writing:
void arraytest(int a)
has the same meaning as writing:
void arraytest(int *a)
So despite you are not writing it explicitly it is as you are passing a pointer and so you are modifying the values in the main.
For more I really suggest reading this.
Moreover, you can find other answers on SO here
Passing a multidimensional array as argument to a function.
Passing an one dim array as argument is more or less trivial.
Let's take a look on more interesting case of passing a 2 dim array.
In C you can't use a pointer to pointer construct (int **) instead of 2 dim array.
Let's make an example:
void assignZeros(int(*arr)[5], const int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 5; j++) {
*(*(arr + i) + j) = 0;
// or equivalent assignment
arr[i][j] = 0;
}
}
Here I have specified a function that takes as first argument a pointer to an array of 5 ints.
I can pass as argument any 2 dim array that has 5 columns:
int arr1[1][5]
int arr1[2][5]
...
int arr1[20][5]
...
You may come to an idea to define a more general function that can accept any 2 dim array and change the function signature as follows:
void assignZeros(int ** arr, const int rows, const int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
*(*(arr + i) + j) = 0;
}
}
}
This code would compile but you will get a runtime error when trying to assign the values in the same way as in the first function.
So in C a multidimensional arrays are not the same as pointers to pointers ... to pointers. An int(*arr)[5] is a pointer to array of 5 elements,
an int(*arr)[6] is a pointer to array of 6 elements, and they are a pointers to different types!
Well, how to define functions arguments for higher dimensions? Simple, we just follow the pattern!
Hier ist the same function adjusted to take an array of 3 dimensions:
void assignZeros2(int(*arr)[4][5], const int dim1, const int dim2, const int dim3) {
for (int i = 0; i < dim1; i++) {
for (int j = 0; j < dim2; j++) {
for (int k = 0; k < dim3; k++) {
*(*(*(arr + i) + j) + k) = 0;
// or equivalent assignment
arr[i][j][k] = 0;
}
}
}
}
How you would expect, it can take as argument any 3 dim arrays that have in the second dimensions 4 elements and in the third dimension 5 elements. Anything like this would be ok:
arr[1][4][5]
arr[2][4][5]
...
arr[10][4][5]
...
But we have to specify all dimensions sizes up to the first one.
@Bo Persson correctly states in his great answer here:
=================================================
When passing an array as a parameter, this
void arraytest(int a)
means exactly the same as
void arraytest(int *a)
=================================================
However, let me add also that it:
means exactly the same as
void arraytest(int a[0])
which means exactly the same as
void arraytest(int a[1])
which means exactly the same as
void arraytest(int a[2])
which means exactly the same as
void arraytest(int a[1000])
etc.
As a matter of fact, the "size" value inside the array parameter here is apparently just for aesthetic/self-documentation purposes, and can be any positive integer (size_t
type I think) you want!
size_t
In practice, however, you should use it to specify the minimum size of the array you expect the function to receive, so that when writing code it's easy for you to track and verify. The MISRA-C-2012 standard (buy/download the 236-pg 2012-version PDF of the standard for £15.00 here) goes so far as to state:
Rule 17.5 The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements.
...
If a parameter is declared as an array with a specified size, the corresponding argument in each function call should point into an object that has at least as many elements as the array.
...
The use of an array declarator for a function parameter specifies the function interface more clearly than using a pointer. The minimum number of elements expected by the function is explicitly stated, whereas this is not possible with a pointer.
[emphasis added]
In other words, they recommend using the explicit size format, even though the C standard technically doesn't enforce it--it at least helps clarify to you as a developer, and to others using the code, what size array the function is expecting you to pass in.
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
You are passing the array by reference but you are modifying its contents - hence why you are seeing a change in the data
– Shaun Wilde
Jul 4 '11 at 5:58