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 ar开发者_如何学Pythonray. 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?
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.
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.)
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));
}
"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.
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]);
From the online C standard:
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
Assume the following code snippet:
int a[10];
...
foo(a);
In the call to foo
, the type of the expression a
is "10-element array of int
". However, since the expression is not the operand of either the sizeof
or &
operators, and since it isn't a string literal being used to initialize another array in a declaration, its type is implicitly converted ("decays") from "10-element array of int
" to "pointer to int
", and its value will be the address of the first element in the array (i.e. &a[0]
).
Therefore, what foo
receives is a pointer to int
, not an array. Dereferencing or subscripting this pointer allows you to change the values of the array.
This is a feature of the C language; arrays are not first-class objects. In fact, in most circumstances (including subscripting) array expressions will be converted to pointer types.
I keep emphasizing the word expression to distinguish between the actual array object (which is always and forever an array type) and any reference to that object in the code, which may be converted to a pointer type.
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.
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.
精彩评论