13

I know for sure that

function(int *a); function(int a[]);

in C are the same, function(int a[]) will be translated into function(int *a)

int *a = malloc(20);
int b[] = {1,2,3,4,5};

These two are not the same, the first is a pointer, the second is an array. What happens when I call function(b)?(function(int *a)) I know that b is on the stack, so how is passed to that function?

Secondly, strings:

char *c1 = "string";
char c2 [] = "string";

In this case I don't know where is c1, and I suppose that c2 is on the stack. Suppose that function now is: function(char *c), which is the same as function(char c[]), what happens when I call function(c1), and function(c2), the strings will be passed by reference or value?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
AR89
  • 3,548
  • 7
  • 31
  • 46

6 Answers6

21

There's a crucial point to make here, everything is really passed by value for example, this will pass a copy of a to foo() (which happens to be a pointer to some memory):

int *a = malloc(20);
foo(a);

That's why if you do something like this in foo() it doesn't really change the pointer a in main() but changes the local copy:

foo(int *a)
{
  a = NULL; /*changes local copy of the pointer*/
}

In other words, you can use foo()'s local copy of a to change the memory pointed to by 'a' but not to change what a points to in main().

Now, to pass something "by reference" you pass a copy of a pointer-to-pointer to the function (something like a->b->memory):

int *a = malloc(20);
foo(&a);

So when you assign to it in foo() to changes the pointer in main():

foo(int **a)
{
  *a = NULL; /*changes the pointer in main */
}

Now to answer some of your other questions, when you use an array name it is converted to a pointer to the first element of the array:

int *a = malloc(20);
int b[] = {1,2,3,4,5};
foo(a);
foo(b);

The last two function calls are equivalent in that they both pass a pointer to the first element of some memory, the difference is the memory for a is allocated on the heap, the memory of b however, is allocated on the stack.

Finally, strings, the following are similar, in that the same principle applies, however the first one is a constant string literal and should be defined as const and you should not attempt to modify it anywhere but you can change the second one:

const char *c1 = "string";
char c2 [] = "string";

 

dud3
  • 409
  • 1
  • 6
  • 16
iabdalkader
  • 17,009
  • 4
  • 47
  • 74
  • 6
    While this is correct, it isn't really pedagogical for a beginner. It is best to state that `func (int x)` is by value and `func (int* x)` is by reference. Because whether it is by val or by ref really depends on the _intention_ of the function. Otherwise one can just say that your example `foo(int **a)` doesn't pass anything by reference, it is merely passing a pointer-to-pointer by value. – Lundin Nov 19 '12 at 07:46
  • 3
    @Lundin I think, IMHO, that saying that something is passed by reference is the reason why all beginners try to assign to a pointer inside a function and expect that it changes it somewhere else. – iabdalkader Nov 19 '12 at 07:50
  • 2
    A beginner with no programmer experience is probably less likely to do that, than lets say a Java programmer learning C. Anyway, all beginners also try to return a pointer to a local variable from a function. I feel that fuzzy terms like "by reference", or indeed "pointer", isn't really helpful to a beginner, it is likely better to explain what is going on in the binary, beneath the hood. – Lundin Nov 19 '12 at 07:58
7

From K&R2

When an array name is passed to a function, what is passed is the 
location of the initial element. Within the called function, this 
argument is a local variable, and so an array name parameter is a 
pointer, that is, a variable containing an address.

The argument declaration char c2 [] is just syntactic sugar for char* c2.

Everything in C gets passed as value. For further explanation of this use this link.

Also Eli Bendersky has an excellent article discussing the same.

Community
  • 1
  • 1
Shash
  • 4,160
  • 8
  • 43
  • 67
0
      int *a = malloc(20);
                         ===========
    |a|----------------> | | | | | |  
                         ===========
    a is a pointer          20 bytes on heap each of 4 bytes 
    to int on stack 


    int b[] = {1,2,3,4,5};


     =================================
     |   1 |  2   |  3  |  4  |  5   |
     =================================
     b[0]   b[1]    b[2]  b[3]   b[4]   
Full array is on stack


char *c1 = "string";
char c2 [] = "string";


In case of "string" it's string literal and allocated on readonly memory.

In first case , |c1| ----> |s|t|r|i|n|g|\0|

In second case ,  ============================================
                  | s  |  t   |   r  |  i  |  n  |  g  | \0  |
                  ============================================
                  c2[0] c2[1]   c2[2] c2[3] c2[4] c2[5]  c2[6]

The full char array is on stack.
Omkant
  • 9,018
  • 8
  • 39
  • 59
  • If you do `char c2[] = "string"` it won't be in readonly memory. – Dietrich Epp Nov 19 '12 at 07:40
  • string will be on `readonly ` a copy of it is copied to `c2` array on stack. – Omkant Nov 19 '12 at 07:42
  • That's one possible way to implement it, but you're talking about implementation details. The end result is something that is not in readonly memory. – Dietrich Epp Nov 19 '12 at 07:44
  • @DietrichEpp Technically, the literal "string" will always be placed in read-only memory, but the compiler is free to optimize away its allocation there, and only allocate space for c2. That is, if the compiler is written for a pure RAM-based system such as a PC. Otherwise, nothing can be done and the string literal must be allocated in ROM. – Lundin Nov 19 '12 at 07:52
  • @Lundin: Technically, there is no requirement that read-only memory exist at all (I can think of a couple C implementations that don't have it), the only thing we can be sure of is that `c2` isn't in read-only memory. – Dietrich Epp Nov 19 '12 at 08:01
-1

If your think it's Call by Value then try to run this:

void bubbleSort(int a[],int n){            //or int *a
    printf("\nBUBBLE SORT");
    int i,j;
    for(i=n-1;i>0;i--)
        for(j=0;j<i;j++)
            if(a[j]>a[j+1])
                swap(&a[j],&a[j+1]);
    displayArray(a,n);
}
main(){
    int n=5,a[n],i,j;
    initArray(a,n);
    displayArray(a,n);
    bubbleSort(&a,n);
    displayArray(a,n);
}

In both bubbleSort() and displayArray() after bubblesort() call, will show same results.

If you call function(a) when a is an array, it will actually pass the Base Address of a. So, its basically Call by Ref.

ALso,

char *c="blah-blah"; and,
char c[]="blah-blah";

are exactly SAME ! In both cases, c points to the first element in the string. Also, the 1st string is NOT and I mean NOT constant. Try changing it. It will.

-2

EDIT: This answer below is wrong.
"Arrays are always passed by reference." This is wrong. See iabdalkader's answer for the why part. However, I am keeping this answer below, for the encapsulation in the struct trick, to pass the copy of the array to a function.


Arrays are always passed by reference (pointer).

If you want to pass them using value, encapsulate them in a struct. That would result in operating on a copy of original array. Example shown below:

The first argument to foo is struct object, which holds a copy of the array. Second argument is array reference.

#include <stdio.h>

struct a{
    int i[2]; // An array encapsulated in struct.
};

void foo(struct a b, int j[]){
    b.i[0]=30;
    j[1]=30;
}

int main(){
    struct a c;
    c.i[0]=10;
    c.i[1]=20;
    printf("Before %d %d\n",c.i[0], c.i[1]);
    foo(c, c.i);
    printf("After %d %d \n",c.i[0], c.i[1]);
    return 0;
}


$ ./a.out 
Before 10 20
After 10 30 
anishsane
  • 20,270
  • 5
  • 40
  • 73
-3

The arrays are passed by reference why ? because you passed the pointer address by value so changing on that pointer will change on the pointed memory not the pointer address itself, so changing the pointer will not replace the original pointer out the function, so when you type a = ANOTHER_POINTER inside that function it will not loss the passed array after using the function

int a[] is equivalent to int a and when calling the function foo(int a) it will get the pointer address

now if you want to change the pointer it self you can pass the pointer address by reference foo(int *& a) so now changing on the pointer address a = ANOTHER_POINTER will change address of the pointer

Omar Freewan
  • 2,678
  • 4
  • 25
  • 49
  • thanks for mentioning foo(int *& a) as a way to change the original pointer. – AR89 Nov 19 '12 at 09:58
  • 2
    No, you cannot pass the pointer address through the C++ reference mechanism in the C language. `foo(int *& a)` will not compile. – Lundin Nov 19 '12 at 14:14