Passing an array as an argument to a function in C

The name of the pictureThe name of the pictureThe name of the pictureClash 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?





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




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.





okay got it! so arrays are not passed by values at all!
– Mohan Mahajan
Jul 4 '11 at 6:23





Which notation is better under which circumstances?
– Ramon Martinez
Sep 4 '15 at 12:07





@Ramon - I would use the second option, as it seems less confusing and better indicates that you don't get a copy of the array.
– Bo Persson
Sep 4 '15 at 12:20





Can you explain the "historical reasons"? I suppose passing by values would need a copy and so a waste of memory.. thanks
– f126ck
Nov 1 '16 at 20:15





@lucapozzobon - Originally C didn't have any pass by value, except for single values. It wasn't until struct was added to the language that this was changed. And then it was considered too late to change the rules for arrays. There were already 10's of users. :-)
– Bo Persson
Nov 2 '16 at 9:26


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")





If I pass an array to a function . Say for example I made an array int a[10] and assigned each element random value . Now if I pass this array to a function using int y or int y[10] or int *y .And then in that function I use sizeof(y) Answer will be the bytes pointer has been allocated. So in this case ,it will decay as a pointer , It Would Be Helpfull If You include this too. See this postimg.org/image/prhleuezd
– Suraj Jain
Sep 30 '16 at 5:08




int a[10]


int y


int y[10]


int *y


sizeof(y)





If I use sizeof operate in the function in the originally we defined array then it will decay as an array , but if I pass in other function then there use sizeof operator it will decay as a pointer.
– Suraj Jain
Sep 30 '16 at 5:09




sizeof


sizeof





stackoverflow.com/questions/8269048/…
– Suraj Jain
Sep 30 '16 at 5:14



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)





I suppose there are () missing for *a+1 should be *(a+1)
– ShinTakezou
Jul 4 '11 at 6:17





@Shin Thanks, been a while since I've played with C.
– alex
Jul 4 '11 at 6:18



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.

Popular posts from this blog

Stripe::AuthenticationError No API key provided. Set your API key using “Stripe.api_key = ”

CRM reporting Extension - SSRS instance is blank

Keycloak server returning user_not_found error when user is already imported with LDAP