Costagero
Costagero

Reputation: 361

Passing an Array by reference in C

I'm new to C and I have a doubt.

Since C functions create local copies of it's arguments, I'm wondering why the following code works as expected:

void function(int array[]){

    array[0] = 4;
    array[1] = 5;
    array[2] = 6;   
}

int main(){

    int array[] = {1,2,3};

    function(array);

    printf("%d %d %d",array[0],array[1],array[2]);

    return 0;
}

With the line output being 4 5 6.

Why does this work while the following doesn't?

void function(int integer){

    integer = 2;
}

int main(){

    int integer = 1;

    function(integer);

    printf("%d",integer);

    return 0;
}

The output is just 1 in this case.

Short version: Why can functions modify the values of their parent variables if they are passed as array?

Thank you all!

Upvotes: 24

Views: 100673

Answers (5)

kfsone
kfsone

Reputation: 24249

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.

Upvotes: 31

StarkOverflow
StarkOverflow

Reputation: 39

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;
}

Upvotes: 3

user2502921
user2502921

Reputation:

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.

Upvotes: 1

Rami
Rami

Reputation: 7290

The array name is a pointer to the first element in the array. In the first code sample you have passed a pointer to the memory location containing the first array element. In the second code sample you have passed an integer by value so it has nothing to do with the local variable named "integer"

check that link

Pass by reference and pass by value

Pass by Reference / Value in C++

Upvotes: 0

Mazzy
Mazzy

Reputation: 1944

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

Upvotes: 1

Related Questions