Passing Arrays by Value and by Reference

Passing Arrays by Value and by Reference

The key to understanding this is to know the difference between a value type and a reference type.

For example, consider a typical value type, int.

int a = 1;
int b = a;
a++;

After this code has executed, a has the value 2, and b has the value 1. Because int is a value type, b = a takes a copy of the value of a.

Now consider a class:

MyClass a = new MyClass();
a.MyProperty = 1;
MyClass b = a;
a.MyProperty = 2;

Because classes are reference types, b = a merely assigns the reference rather than the value. So b and a both refer to the same object. Hence, after a.MyProperty = 2 executes, b.MyProperty == 2 since a and b refer to the same object.


Considering the code in your question, an array is a reference type and so for this function:

public static void FirstDouble(int[] array)

the variable array is actually a reference, because int[] is a reference type. So array is a reference that is passed by value.

Thus, modifications made to array inside the function are actually applied to the int[] object to which array refers. And so those modifications are visible to all references that refer to that same object. And that includes the reference that the caller holds.

Now, if we look at the implementation of this function:

public static void FirstDouble(int[] array)
{
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;

//create new object and assign its reference to array
array = new int[] { 11, 12, 13 };
}

there is one further complication. The for loop simply doubles each element of the int[] that is passed to the function. That's the modification that the caller sees. The second part is the assignment of a new int[] object to the local variable array. This is not visible to the caller because all it does is to change the target of the reference array. And since the reference array is passed by value, the caller does not see that new object.

If the function had been declared like this:

public static void FirstDouble(ref int[] array)

then the reference array would have been passed by reference and the caller would see the newly created object { 11, 12, 13 } when the function returned.

Are arrays passed by value or passed by reference in Java?

Your question is based on a false premise.

Arrays are not a primitive type in Java, but they are not objects either ... "

In fact, all arrays in Java are objects1. Every Java array type has java.lang.Object as its supertype, and inherits the implementation of all methods in the Object API.

... so are they passed by value or by reference? Does it depend on what the array contains, for example references or a primitive type?

Short answers: 1) pass by value, and 2) it makes no difference.

Longer answer:

Like all Java objects, arrays are passed by value ... but the value is the reference to the array. So, when you assign something to a cell of the array in the called method, you will be assigning to the same array object that the caller sees.

This is NOT pass-by-reference. Real pass-by-reference involves passing the address of a variable. With real pass-by-reference, the called method can assign to its local variable, and this causes the variable in the caller to be updated.

But not in Java. In Java, the called method can update the contents of the array, and it can update its copy of the array reference, but it can't update the variable in the caller that holds the caller's array reference. Hence ... what Java is providing is NOT pass-by-reference.

Here are some links that explain the difference between pass-by-reference and pass-by-value. If you don't understand my explanations above, or if you feel inclined to disagree with the terminology, you should read them.

  • http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/com.ibm.xlcpp8a.doc/language/ref/cplr233.htm
  • http://www.cs.fsu.edu/~myers/c++/notes/references.html

Related SO question:

  • Is Java "pass-by-reference" or "pass-by-value"?

Historical background:

The phrase "pass-by-reference" was originally "call-by-reference", and it was used to distinguish the argument passing semantics of FORTRAN (call-by-reference) from those of ALGOL-60 (call-by-value and call-by-name).

  • In call-by-value, the argument expression is evaluated to a value, and that value is copied to the called method.

  • In call-by-reference, the argument expression is partially evaluated to an "lvalue" (i.e. the address of a variable or array element) that is passed to the calling method. The calling method can then directly read and update the variable / element.

  • In call-by-name, the actual argument expression is passed to the calling method (!!) which can evaluate it multiple times (!!!). This was complicated to implement, and could be used (abused) to write code that was very difficult to understand. Call-by-name was only ever used in Algol-60 (thankfully!).

UPDATE

Actually, Algol-60's call-by-name is similar to passing lambda expressions as parameters. The wrinkle is that these not-exactly-lambda-expressions (they were referred to as "thunks" at the implementation level) can indirectly modify the state of variables that are in scope in the calling procedure / function. That is part of what made them so hard to understand. (See the Wikipedia page on Jensen's Device for example.)


1. Nothing in the linked Q&A (Arrays in Java and how they are stored in memory) either states or implies that arrays are not objects.

Difference between passing an array by value and reference in C++

The first one decays to a pointer to the first element in the array, the second is an actual reference to the array.

They're different in the same way that pointers and references are generally different.

Specifically, in the case of arrays, a reference to the array is useful because you retain the ability to determine the size of the array. This frees you from having to pass the size/length of the array as a separate parameter as you would in a C API.

One way of implementing this that I think is particularly slick involves templates. Using a template parameter, you can get the compiler to automatically deduce the size of the array. For example:

void ProcessArray(int* pArray, std::size length)
{
for (std::size_t i = 0; i < length; ++i)
{
// do something with each element in array
}
}

template <std::size_t N>
void ProcessArray(int (&array)[N])
{
ProcessArray(array, N); // (dispatch to non-template function)
}

Pass Array by Reference in C

Arrays are always passed by reference in C. The name of the array is pointer to the first element of it. So, you just do this :-

void function (int arr[]){
// Some Code.....
}
int main(){
// Some Code...
int name[5];
function(name);
// Some Code...
}

And that would work, you can modify the values of elements in the array and the changes would be reflected in the calling function.

Edit: You know that you have to add a semi-colon after your for loop? Otherwise the next one line will also be iterated. See -

Corrected Code
and
Output

Passing array by value in c#

As far is i understand, the default type or argument passing in c# is by value.

Unfortunately it is a bit more complicated and also has some execptions:

Reference types like Decomposition you hand in by making a copy of the reference. Unfortunately that means both still reference the same instance in memory. So despite a copy operation, it is call-by-Reference.

With value types like Int or double and their aliases, usually a copy is made. I do not know of any case where it does not, but I was wrong on those things before. So they are call by value.

Finally String and a few other reference types are inmutable by design. That has the advantage that they behave kinda like value types in this area. You hand in a Reference, but the instance itself can not be changed. The code can only create a new instance in memory with a different value. So despite handing over literal references, it kinda works like call by value.

Your specific case

Arrays are very explicitly Reference types. Handing them into a function without side effects, requires proper cloning. If it is a array of reference types, the cloning must be deep.

In your case you have arrays of value types. If you want to avoid call-by-reference side effects, you those arrays must be cloned. However as double is a value type, this cloning can be shallow. No need for a deep clone.

Unlike Java there is not a dedicated Clone() Method. And I am not sure why exactly. However you can often use one Collection to initialize another through the constructor. Or they even have a function like Array.Copy(), as TheBatman pointed out.

Passing an Array by reference in C

This is caused by the fact that arrays tend to decay into pointers.

int a[] = { 1, 2, 3 };
int* p = a; // valid: p is now the address of a[0]
a = p; // NOT valid.

printf("a = %p\n", a);
printf("p = %p\n", p); // prints same address as a

a and p will print the same value.

Contrary to what others have said, a is not a pointer, it can simply decay to one. http://c-faq.com/aryptr/aryptrequiv.html

In your first function() what gets passed is the address of the array's first element, and the function body dereferences that. Infact, the compiler is treating the function prototype as this:

void function(int* array /*you wrote int array[]*/){
array[0] = 4;
array[1] = 5;
array[2] = 6;
}

function(&array[0]);

This has to happen because you said "array of unknown size" (int array[]). The compiler could not guarantee to deduce the amount of stack required to pass by value, so it decays to a pointer.

---- Edit ----

Lets combine both your examples and use more distinctive names to make things clearer.

#include <stdio.h>

void func1(int dynArray[]) {
printf("func1: dynArray = %p, &dynArray[0] = %p, dynArray[0] = %d\n",
dynArray, &dynArray[0], dynArray[0]);
}

void func2(int* intPtr) {
printf("func2: intPtr = %p, &intPtr[0] = %p, intPtr[0] = %d\n",
intPtr, &intPtr[0], intPtr[0]);
}

void func3(int intVal) {
printf("func3: intVal = %d, &intValue = %p\n",
intVal, &intVal);
}

int main() {
int mainArray[3] = { 1, 2, 3 };
int mainInt = 10;

printf("mainArray = %p, &mainArray[0] = %p, mainArray[0] = %d\n",
mainArray, &mainArray, mainArray[0]);
func1(mainArray);
func2(mainArray);

printf("mainInt = %d, &mainInt = %p\n",
mainInt, &mainInt);
func3(mainInt);

return 0;
}

Live demo at ideone: http://ideone.com/P8C1f4

mainArray = 0xbf806ad4, &mainArray[0] = 0xbf806ad4, mainArray[0] = 1
func1: dynArray = 0xbf806ad4, &dynArray[0] = 0xbf806ad4, dynArray[0] = 1
func2: intPtr = 0xbf806ad4, &intPtr[0] = 0xbf806ad4, intPtr[0] = 1

mainInt = 10, &mainInt = 0xbf806acc
func3: intVal = 10, &intValue = 0xbf806ad0

In func1 and func2 "dynArray" and "intPtr" are local variables, but they are pointer variables into which they receive the address of "mainArray" from main.

This behavior is specific to arrays. If you were to put the array inside a struct, then you would be able to pass it by value.

Pass an array by value

It is possible to do this by wrapping the array in a struct. You can include a field for the size of the array so that you don't need to pass this parameter explicitly. This approach has the virtue of avoiding extra memory allocations that must later be freed.

C already passes arguments to functions by value, but array identifiers decay to pointers in most expressions, and in function calls in particular. Yet structs do not decay to pointers, and are passed by value to a function, meaning that a copy of the original structure and all of its contents is visible in the scope of the function. If the struct contains an array, this is copied too. Note that if instead the struct contains, say, a pointer to int for a dynamic array, then the pointer is copied when the struct is passed to the function, but the same memory is referenced by both the copy and the original pointer. This approach relies on the struct containing an actual array.

Also note that a struct can not contain a member with an incomplete type, and so can not contain a VLA. Here I have defined the global constant MAX_ARR to be 100 to provide some space for handling differently sized arrays with the same struct type.

You can also return a struct from a function. I have included an example which modifies the Array struct which is passed into a function, and returns the modified struct to be assigned to a different Array struct in the calling function. This results in the caller having access to both the original and the transformed arrays.

#include <stdio.h>

#define MAX_ARR 100

struct Array {
size_t size;
int array[MAX_ARR];
};

void print_array(struct Array local_arr);
void func(struct Array local_arr);
struct Array triple(struct Array local_arr);

int main(void)
{
struct Array data = {
.size = 10,
.array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
};
struct Array transformed_data;

func(data);
transformed_data = triple(data);

printf("Original\n");
print_array(data);

printf("Transformed\n");
print_array(transformed_data);

return 0;
}

void print_array(struct Array local_arr)
{
for (size_t i = 0; i < local_arr.size; i++) {
printf("%5d", local_arr.array[i]);
}
putchar('\n');
}

void func(struct Array local_arr)
{
for (size_t i = 0; i < local_arr.size; i++) {
local_arr.array[i] *= 2;
}
printf("Modified\n");
print_array(local_arr);
}

struct Array triple(struct Array local_arr)
{
for (size_t i = 0; i < local_arr.size; i++) {
local_arr.array[i] *= 3;
}
return local_arr;
}

Program output:

Modified
2 4 6 8 10 12 14 16 18 20
Original
1 2 3 4 5 6 7 8 9 10
Transformed
3 6 9 12 15 18 21 24 27 30

C pass array by value vs pass array by reference

In C passing by reference means passing an object indirectly through a pointer to it. If you will pass an object directly to a function then the function will deal with a copy of the value of the object.

Compare two function calls in this demonstrative program.

#include <stdio.h>

void f( int x )
{
x = 10;
}

void g( int *x )
{
*x = 10;
}

int main(void)
{
int x = 0;

printf( "Before call f: x = %d\n", x );

f( x );

printf( "After call f: x = %d\n", x );

putchar( '\n' );

printf( "Before call g: x = %d\n", x );

g( &x );

printf( "After call g: x = %d\n", x );

return 0;
}

The program output is

Before call f: x = 0
After call f: x = 0

Before call g: x = 0
After call g: x = 10

That is we passed to the function f the object x directly. So the function deals with a copy of the object x. Changing the copy does not influence on the original object x declared in main.

As for the function g then it got an access to the object x indirectly through a pointer to it. So changing the pointed object we changed the object x declared in main.

As for arrays then when an array is passed to a function it is implicitly converted to pointer to its first element. So the function in fact gets elements of the array by reference through this pointer. Using the pointer and the pointer arithmetic we can change any element of the array.

This function declaration

void set_array(int array[4]);

is equivalent to the following declaration

void set_array(int array[]);

and the both declarations are adjusted by the compiler to the declaration

void set_array(int *array);

So the function deals with a pointer - the pointer to the first element of the array used as an argument of the function call.

The call of the function set_array in your program

set_array(b);

is equivalent to the following call

set_array( &b[0] );

because arrays used in expressions as for example as a function argument expression are implicitly converted to pointers to their first elements.

Passing an array by reference in C?

In C arrays are passed as a pointer to the first element. They are the only element that is not really passed by value (the pointer is passed by value, but the array is not copied). That allows the called function to modify the contents.

void reset( int *array, int size) {
memset(array,0,size * sizeof(*array));
}
int main()
{
int array[10];
reset( array, 10 ); // sets all elements to 0
}

Now, if what you want is changing the array itself (number of elements...) you cannot do it with stack or global arrays, only with dynamically allocated memory in the heap. In that case, if you want to change the pointer you must pass a pointer to it:

void resize( int **p, int size ) {
free( *p );
*p = malloc( size * sizeof(int) );
}
int main() {
int *p = malloc( 10 * sizeof(int) );
resize( &p, 20 );
}

In the question edit you ask specifically about passing an array of structs. You have two solutions there: declare a typedef, or make explicit that you are passing an struct:

struct Coordinate {
int x;
int y;
};
void f( struct Coordinate coordinates[], int size );
typedef struct Coordinate Coordinate; // generate a type alias 'Coordinate' that is equivalent to struct Coordinate
void g( Coordinate coordinates[], int size ); // uses typedef'ed Coordinate

You can typedef the type as you declare it (and it is a common idiom in C):

typedef struct Coordinate {
int x;
int y;
} Coordinate;


Related Topics



Leave a reply



Submit