Passing an Array by reference in C

Solution 1:

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.

Solution 2:

An array passed to a function is converted to a pointer. When you pass a pointer as argument to a function, you simply give the address of the variable in the memory. So when you modify the value of the cell of the array, you edit the value under the address given to the function.

When you pass a simple integer to a function, the integer is copied in the stack, when you modify the integer within the function, you modify the copy of the integer, not the original.

Reminder of the different kinds of memory in C

In C, we can use three types of memory :

  • the stack, used for local variables and functions calls: when we create a variable in main(), we use the stack to store the variable, and when a function is called, the parameters given to the method are register in the stack. When we exit a function, we "pop" these parameters to return to the original state, with the used variable before the call of the function. (anecdote: a stackoverflow is when we hack the stack to use previous variables in a function without passing it as parameters)
  • the heap which corresponds to the dynamicly allocated memory: when we need large amount of data, we use this heap because the stack is limited to a few megabytes.
  • the code where the program instructions are stored

In the case of this array passed by a function, which is a pointer (address to an other variable), it is stored in the stack, when we call the function, we copy the pointer in the stack.

In the case of the integer, it is also stored in the stack, when we call the function, we copy the integer.

If we want to modify the integer, we can pass the address of the integer to modify the value under the pointer, like this:

void function(int *integer)
{
    *integer = 2;
}

int main()
{
    int integer = 1;
    function(&integer);

    printf("%d", integer);

    return 0;
}

Solution 3:

There is a difference between 'pass by reference' and 'pass by value'

Pass by reference leads to a location in the memory where pass by value passes the value directly, an array variable is always an refference, so it points to a location in the memory. Integers will pass by value by default

Solution 4:

In the first code, you are passing the address of the array pointing to the top element in the array. So, when you modify the value in the function and return to the main function you are still accessing the same array which is in the same address. This is called pass by reference.

However, in the second case, the value of the integer is copied from the main function to the called function. In other words, the two integers are in different address in the memory. So modifying one does not modify the other.