tags:

views:

215

answers:

8

when we pass an element of an array to a function, it is treated as an normal variable and the called function creates a copy of the actual argument and operates on it.Any changes made in the formal arguments doesn't affect the actual arguments.

But this not the case when we pass a whole array. In this case it(called function) gets access to the actual arguments and any changes made in the formal arguments affects the actual arguments. Why this happens ?

+8  A: 

The array is passed as a pointer to the elements.

If I write:

void doStuff(int *ptr)
{
  ptr[1] = 5;
}

int main()
{
  int arr[] = {0, 1, 2};
  doStuff(arr);
  printf("%d %d %d\n", arr[0], arr[1], arr[2]);
}

the output will be "0 5 2". That's because C passes whatever is actually the parameter by value. The parameter is a pointer to an int. So a pointer to an int is passed by value. Thus, doStuff gets a copy of a pointer to memory in main's stack frame. When it dereferences that pointer with ptr[1], it is following the pointer to main's memory and modifying the array there.

C can only pass by value, but it does so "shallowly". If you ask it to pass an int *, it will pass an int *. It only copies the value of the pointer, not the values of anything it points to.

If you want doStuff to get its own copy of the array, either wrap the array in a struct as others have suggested, or use memcpy to manually deep copy the array like this:

void doStuff(int *ptr, int nElems)
{
  int myCopyOfTheArray[nElems];
  memcpy(myCopyOfTheArray, ptr, sizeof(int) * nElems);
  /* do stuff with the local copy */
}

Unlike using a struct, the memcpy approach works if nElems is only know at runtime.

Jon Rodriguez
The 2nd code snippet, is it valid C or just pseudo C???
Nyan
Ok, What compiler are you using? just curious.
Nyan
gcc version 4.1.2
Jon Rodriguez
Oops, shit. You're right if you were pointing out that I shouldn't be freeing a stack array!
Jon Rodriguez
Holy crap and I misdeclared the array! It wasn't valid C at all! Sorry, I'm coming off an all-nighter and it's 8:30 am here. :-/
Jon Rodriguez
@Nyan meant to address the prev two comments to you. You were right.
Jon Rodriguez
A: 

An array in C may be treated as a pointer to the first element of the array. The pointer is passed by-value (you cannot modify the value passed in), but you can dereference it and modify the memory that it points at.

Jonathan
An array in C is not a pointer, it's often *demoted* to a pointer.
Matteo Italia
@Matteo, @paxdiablo Fixed.
Jonathan
+7  A: 

Arrays can't be passed by value in C. They get demoted to pointers. So the called function sees a pointer to the array (passed by reference) and operates on it. If you want to make a copy, you have to either do so explicitly, or put your array inside a struct (which can be passed by value to functions.)

Nathon
A: 

Because when You pass a whole array to function You pass a pointer to that array, which means that You give function a place in memory where this array is located. So when You change the array in function You are changing the original array as well.

Vasilij
+3  A: 

It is expensive to make a copy of a whole array, in general. Back in the days when C was first created, it could easily exhaust the machine resources (stack in particular).

If you really want to pass an array, wrap it in a structure:

struct wrap { int array[100]; };

int somefunc(struct wrap large) { ... }

void anotherfunc(void)
{
    struct wrap a;
    ...add data to array...
    printf("%d\n", somefunc(a));
}
Jonathan Leffler
+1  A: 

"Pass by reference" is a red herring in C. All arguments to a function are "passed by value" only. In case of arrays, you pass the address of the first element in the form of a pointer. You can then use this pointer to refer to the desired memory location & read or write values.

Kedar Soparkar
+1  A: 
John Bode
+2  A: 

I haven't really seen any answers yet cover the whole question yet. From what I see, it looks like the question asks something like this:

Given the following code:

int a[5];

foo(a);
bar(a[0]);

Why can foo manipulate the original values while bar receives only a copy of the value being passed in?

This is because of the use of array notation: the [] operator dereferences the item it references in the array and passes in the value at that location.

So

int a[5];
bar(a[0]);

is different than:

int* a;
bar(a);

If you want to pass in a references to a specific item in an array, you need to use the & operator:

bar(&a[5]);
Brazzle