0

I'm trying to understand the difference between pass by value and pass by reference, and I thought that I finally understand it, until I saw this code :

void change(char *p1)

{
    p1="new";
}

int main()

{
    char *txt1=(char*)malloc(200*sizeof(char));
    
    txt1="original";
    printf("before :%s\n",txt1);
    change(txt1);
    printf("after :%s\n",txt1);
    
}

Isn't it passing an address ? and then changing it and making it point to somewhere else ?

The output is :

before : original

after : original

Why is that?

Community
  • 1
  • 1
  • 2
    Technically, C doesn't support anything but pass by value. – Some programmer dude Jun 05 '16 at 14:01
  • @JoachimPileborg: "Technically"? In what aspect does it support pass by reference more than any other turing-complete language? – too honest for this site Jun 05 '16 at 14:08
  • C, C++, Java, and any language I have ever heard of uses pass by value. But you can pass references (or pointers) by value, that makes it a bit confusing. – alain Jun 05 '16 at 14:31
  • So many great answers to the questions, that it perhaps isn't worth adding another one - I'll just comment. (1) `printf()` is a great debugging helper. Had you added the following line: `printf("%p %s\n", &p1, p1);` _before_ and _after_ `p1="new";` as well as a similar call before and after `change(txt1);`, you would have immediately understood **_why this is passing by value_**. (-: – user3078414 Jun 05 '16 at 14:56

5 Answers5

2

This is passing an address as value. To have the callee modify caller's local variable, pass address of what should be modified.

#include <stdio.h>

void change(char **p1)

{
    *p1="new";
}

int main(void)

{
    char *txt1; /* no causing memory leak */

    txt1="original";
    printf("before :%s\n",txt1);
    change(&txt1);
    printf("after :%s\n",txt1);

}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
2

There is no pass-by-reference in C. Function parameters are passed using pass-by-value. That is, p1 itself is passed by value. You can change the content of the memory address pointed to by p1 (*p1) from the called function, not p1 itself.

To clarify, for changing the content of a variable var, you need to pass the address of var, so, if you want to change a pointer itself, you need to pass the address of the pointer to the function.

That said, please see this discussion on why not to cast the return value of malloc() and family in C.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1

In function call change(txt1);, txt1 is passed by value. It is copied to the parameter p of function change. This makes pi points to the same string as txt1 pointing to. When new string is assigned to p1 then p1 changes to point to that string while txt1 pointing previous one.

this case is very similar to

char *s1 = "String";
char *s2 = s1;        // Both s1 and s2 points to same string  
s2 = "Another string" // Now s2 points to "Another string" while s1 pointing to "String". 

Beside that your code is causing memory leak. It should be like

char *txt1=(char*)malloc(200*sizeof(char));
strcpy(txt1,"original");
haccks
  • 104,019
  • 25
  • 176
  • 264
1

Pass By Reference and Pass By value. Pass By Reference and Pass By value.

Ranjeet Singh
  • 924
  • 5
  • 11
1

Here's an example I've used before. Assume the following two functions:

void foo( T *p ) // where T is an arbitrary data type
{
  *p = new_value(); // write new value to the thing p points to
}

void bar( void )
{
  T var;
  foo( &var );  // write new value to var
}

For function foo to update the contents of var (an object of type T) we must pass a pointer to var (type T *).

If we replace T with a pointer type P *, then the above code becomes

void foo( P **p )
{
  *p = new_value(); // write new value to the thing p points to
}

void bar( void )
{
  P *var;
  foo( &var );  // write new value to var
}

The semantics are exactly the same; we want foo to write a new value to var, so we pass a pointer to var. It's just that in this case, var is already a pointer type, so we wind up passing a pointer to a pointer.

Basically, for foo to update the contents of var, you must pass the expression &var as the argument, meaning the type of the formal parameter p will always have one more level of indirection than the type of var.

Type of var      Type of &var      Type of p
-----------      ------------      ---------
          T               T *            T *
        T *              T **           T **
       T **             T ***          T ***

etc.

John Bode
  • 119,563
  • 19
  • 122
  • 198