0
votes

In the example, adapted from a book, I want to fully understand how passing and array by reference really works. From playing with the below code in Code Blocks and some reading here and there, I get that passing by value doesn't change the initial variable's value ( the example_pass_by_value). As for the other two variables whose adresses are passed by reference to the change function, I only understood the example_pass_by_reference case like this : when calling the function like this "change (&example_pass_by_reference), you actually put and "=" sign between the formal parameter "by_reference" ( this being declared as pointer in the change function definition) and the address of "example_pass_by_reference" variable whic is passed to the change function ( ex: by_reference = 0x6644fe, or better by_reference = &example_pass_by_reference); The thing i don't understand is how the "=" is put between the address of array in the calling of function "change(array, ....) and the formal parameter "int arr[]" from definition of the function "change(int arr[], ...)", since int arr[] is an array, not a pointer, to be able to receive the address of variable "array".( like int arr[] = array, or int arr[] = 0x7856ff, for example); Thank you in advance and sorry for the subsequent errors in my code or language.

#include <stdio.h>
#include <string.h>

main()
{
    int array[3] = {1,2,3};
    int example_pass_by_value = 5;
    int example_pass_by_reference = 6;

    change(array, example_pass_by_value, &example_pass_by_reference);

    printf("Back in main(), the array[1] is now %d.\n", array[1]);
    printf("Back in main(), the example_pass_by_value is now %d.\n, unchanged", example_pass_by_value);
    printf("Back in main(), the example_pass_by_reference is now %d.\n", example_pass_by_reference);
    return(0); 
}

/******************************************************************/

change(int arr[], int by_value, int *by_reference)  
{
    // Changes made to all three variables; 
      arr[1] = 10;
      by_value = 100;
      *by_reference = 1000;
      return; 
}
2
C does not pass anything by reference, it doesn't have references. It passes everything by value, or by pointer, which is a type of value. Are you asking "How do C arrays decay into pointers when used as arguments?" - tadman
@tadman: “Reference” is an English word meaning to mention or allude to something. “Pass by reference” means to provide something by some handle to it, rather than by value. Passing a pointer is such an action. This meaning was in use before C++ existed, and the fact that C++ built references into the language as a primary type does not nullify prior use of the word. The * operator in C is a dereference operator. The C standard says the type a pointer is derived from is the referenced type (C 2018 6.2.5 20). So stop with the nonsense; any way of referring to an object is a reference. - Eric Postpischil
"since int arr[] is an array, not a pointer". You are mistaken. It is a pointer. The [] notation is misleading. It does not denote an array. See e.g. this - n. 1.8e9-where's-my-share m.
@EricPostpischil There's layers to that definition. In the C world you can pass a "reference" to something in pointer form, but that reference itself is passed by value. Perhaps I should rephrase to "C does not implicitly pass anything by reference, you must explicitly pass a pointer". - tadman
@tadmin: Not quite true, when you pass an array, you do not explicitly pass a pointer. It is implicit. It is true to say C does not have implicit references as a primary type, where passing x actually passes the address of x in a hidden way. Regardless, a pointer is a reference, the same way “George Washington” is a reference to George Washington. If it were not a reference, we could not dereference it with the dereference operator. When students refer to passing by reference in C, we are not helping them by saying there is no pass by reference in C… - Eric Postpischil

2 Answers

2
votes

In this function declaration:

void change(int arr[], int by_value, int *by_reference)

C does not support passing arrays as arguments. When you declare a parameter to be an array, the compiler automatically adjusts it to be a pointer. So this declaration is as if it were:

void change(int *arr, int by_value, int *by_reference)

(Note, I added an int before the function declaration. You should always write a return type, such as int or void, before a function that is being declared. Your compiler may insert a default type of int, but that is an old C feature and should not be used anymore.)

To match the automatic adjustment in the declaration, C also automatically converts arrays in arguments (and most other expressions). In the function call:

change(array, example_pass_by_value, &example_pass_by_reference);

The array array is automatically converted to a pointer to its first element, as if it were:

change(&array[0], example_pass_by_value, &example_pass_by_reference);

Now let us look at the code inside the function. This statement:

arr[1] = 10;

says to take the pointer arr, which has the address of the first element of array, add 1 to it, and use the element there. One element beyond array[0] is array[1], so arr[1] refers to array[1]. This statement assigns 10 to it. So array[1] becomes ten. Note that the array was not passed by value, because C automatically converted it to a pointer. The pointer was passed by value, and the pointer gives us a reference to elements of the array, and arr[1] uses that reference to access elements of the array.

This statement:

by_value = 100;

sets the parameter by_value to 100. Since it is only changing the parameter, it does not change the argument example_pass_by_value in the main function.

This statement:

*by_reference = 1000;

uses the pointer by_reference to access an int in memory. The * operator says to use the pointer to refer to the object it points to. So this statement assigns the value 1000 to the int that by_reference points to. The pointer by_reference was passed by value, and it provides a reference to example_pass_by_reference, because the address of example_pass_by_reference was passed as the argument.

1
votes

For starters a typical mistake of whose who do not know C is the statement like that

C does not pass anything by reference, it doesn't have references

C does not have references in the sense as C++ has but it has a mechanism of passing by reference.

You shall not mix the terminology and notions of different languages and shall use the terminology defined in the concrete language.

In C pointers play the role of references. From the C Standard

— A pointer type may be derived from a function type or an object type, called the referenced type. A pointer type describes an object whose value provides a reference to an entity of the referenced type. A pointer type derived from the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a pointer type from a referenced type is called ‘‘pointer type derivation’’. A pointer type is a complete object type.

So to pass by reference in C means passing an object through a pointer to the object.

As for your question then arrays used in expressions (with rare exceptions as for example using in the sizeof operator) are implicitly converted to pointers to their first elements.

You can imagine the following function call

void f( int a[] );

//...
int a[] = { 1, 2, 3, 4, 6 };

f( a );

like

void f( int a[] );

//...
int a[] = { 1, 2, 3, 4, 6 };

int *tmp = a;    
f( tmp );

or that is the same

void f( int a[] );

//...
int a[] = { 1, 2, 3, 4, 6 };

int *tmp = &a[0];    
f( tmp );

On the other hand, a function parameter having an array type is implicitly adjusted by the compiler to pointer to the type of element of the array.

So for example these two function declarations are equivalent and declare the same one function

void f( int a[] );
void f( int *a );

So passing an array to a function you are passing pointer to its first element. It means that in fact all elements of the array are passed by reference. Using the pointer arithmetic you can change any element of the array pointed to by the pointer.

For example this statement

arr[1] = 10;

is evaluated by the compiler like

*( arr + 1 ) = 10;

where arr is a pointer to the first element of an array.