loading...

Passing by value, passing by reference in C

mikkel250 profile image mikkel250 ・3 min read

Basics of the C programming language (20 Part Series)

1) Functions in C 2) Arrays in C 3 ... 18 3) Strings in C 4) String functions in C 5) Setting up VSCode for C in linux 6) Pointer basics in C 7) Advanced pointer operations in C 8) Pointers: Const, Void, and Arrays 9) Pointers arithmetic 10) Pointers and strings 11) Passing by value, passing by reference in C 12) Dynamic memory allocation in C 13) Structures in C 14) Structures and arrays in C 15) Nested structures in C 16) Structures and pointers in C 17) Structures and functions in C 18) File input and output in C 19) Reading file contents in C 20) Writing to files in C

Pass by value

C always uses 'pass by value' to pass arguments to functions (another term is 'call by value', which means the same thing), which means the code within a function cannot alter the arguments used to call the function, even if the values are changed inside the function.
Every other time you pass data to a function (besides scanf), the data outside the function is not modified - it's like a local variable inside the function - that is because C creates a copy of the data that the function uses.

An example of a 'swap' function to demonstrate the difference between pass by value and pass by reference is a simple function that swaps the values of two variables:

void swap(int fistVariable, int secondVariable)
{
  // create a temporary variable to hold one of the values to perform the swap
  int tempVariable;

  tempVariable = firstVariable;  /* temporarily save the value of the first variable */
  firstVariable = secondVariable;  /* swap the vale of the first variable with the value of the second variable */
  secondVariable = tempVariable;  /* put the value of the first variable into the second variable */

  return;
}

int main(void)
{
  int a = 100;
  int b = 200;

  printf("before swap: value of a: %d \n", a);
  printf("before swap: value of b: %d \n", b);

  // call function to swap values
  swap(a, b);

  // check values outside the function after swap function is run
  printf("after swap: value of a: %d \n", a);
  printf("after swap: value of b: %d \n", b);

  return 0;

}

If the code above is run, the values remain the same after the swap function is run. This is because, under the hood, C is passing in copies of the variables (a and b in this case), and they are modified within the function, but the originals remain unaffected.

Pass by reference

Even though C always uses 'pass by value', it is possible simulate passing by reference by using dereferenced pointers as arguments in the function definition, and passing in the 'address of' operator & on the variables when calling the function.
What is passed in is a copy of the pointer, but what it points to is still the same address in memory as the original pointer, so this allows the function to change the value outside the function.
The arguments passed in and worked with inside the function are dereferenced pointers, which, from the programmer's perspective, is essentially the same thing as working with the values themselves.

Using the same structure as the swap function above, using pointers, the values outside the function will be swapped:

void swap(int *pFirstVariable, int *pSecondVariable)
{
  int temp;

// using dereferenced pointers means the function is working with the values at the addresses that are passed in
  temp = *pFirstVariable;
  *pFirstVariable = *pSecondVariable;
  *pSecondVariable = temp;

  return;
}

int main(void)
{
  int a = 100;
  int b = 200;

  printf("before swap: value of a: %d \n", a);
  printf("before swap: value of b: %d \n", b);

  // call the function to swap values, using the 'address of' operator to pass in the address of each variable
  swap(&a, &b);

  // check values outside the function after swap function is run
  printf("after swap: value of a: %d \n", a);
  printf("after swap: value of b: %d \n", b);

  return 0;

}

If the example above is run, the values will be swapped (outside the function) after swap() has been called.

Returning pointers from a function

Returning a pointer from a function is a particularly powerful. It allows you to return not just a single value, but a whole set of values (e.g. structures, covered later). There is a special syntax for declaring a function that returns a pointer:

int * myFunction()
{
  //your code
}

There are specific hazards relating to returning a pointer, so there are some best practices to follow.

  • use local variables to avoid interfering with the variable that the argument points to
Recap
  • use dereferenced pointers in the function definition:
    void swap(int *pFirstVariable, int *pSecondVariable);

  • and use the 'address of' & operator and the variable name when invoking the function if you wish the changed values to be available outside of the function:
    swap(&a, &b);

  • to return a pointer from a function, use an asterisk in front of the function name, and use with care.

Basics of the C programming language (20 Part Series)

1) Functions in C 2) Arrays in C 3 ... 18 3) Strings in C 4) String functions in C 5) Setting up VSCode for C in linux 6) Pointer basics in C 7) Advanced pointer operations in C 8) Pointers: Const, Void, and Arrays 9) Pointers arithmetic 10) Pointers and strings 11) Passing by value, passing by reference in C 12) Dynamic memory allocation in C 13) Structures in C 14) Structures and arrays in C 15) Nested structures in C 16) Structures and pointers in C 17) Structures and functions in C 18) File input and output in C 19) Reading file contents in C 20) Writing to files in C

Posted on Dec 24 '19 by:

mikkel250 profile

mikkel250

@mikkel250

I've been tinkering with computers since I was a teen. I'm currently pivoting from my current role as Tech Support manager to Full Stack Web Developer. I'm actively seeking employment in the field.

Discussion

markdown guide
 

As good and relevant as the content of this article is, and it is; there a small inaccuracy.
You might say that I am very picky, or even splitting hair here.

But, technically, there is no such thing as "passing by reference" in C, there is only "passing by value". And you say it almost clearly when you say that passing pointers is a way to simulate passing by reference. But in the end, C is really passing the value of the pointers (and these values are copied in the execution context of the function just as any other "passing by value"); it just is that you can access the pointed values that are not in the execution context of the function so neither copied as call-time, nor erased at return-time.

A good way to illustrate this would be to modify the values of pointers afters the swap has occurred and show that it does not harm the result:

void swap(int *pFirstVariable, int *pSecondVariable)
{
  int temp;

// using dereferenced pointers means the function is working with the values at the addresses that are passed in
  temp = *pFirstVariable;
  *pFirstVariable = *pSecondVariable;
  *pSecondVariable = temp;

  pFirstVariable = 42;
  pSecondVariable = 78;
}

And while this might be me being picky, it just happens to show how close to the machine C language actually is, and how, languages that actually have "passing by reference" are not doing magic, but merely mildly sophisticated syntactic sugar.

Indeed, Pascal allows to add the keyword var to a function declaration to pass by reference:

procedure swap(var x, y: integer);
var
   temp: integer;

begin
   temp := x;
   x:= y;
   y := temp;
end;

Or C++, that has the confusing & for references:

#include <iostream>

void swap(int& x, int& y) 
{ 
    int z = x; 
    x = y; 
    y = z; 
} 

int main() 
{ 
    int a = 11, b = 22; 
    std::cout << "Before Swap\n"; 
    std::cout << "a = " << a << " b = " << b << "\n"; 

    swap(a, b); 

    std::cout << "After Swap with pass by reference\n"; 
    std::cout << "a = " << a << " b = " << b << "\n"; 
} 

In both cases, you handle the arguments directly without dereferencing them but really you are manipulating the very integers from the outside.

 

Thanks for the clarification! I thought saying "C uses 'pass by value' to pass arguments ..." at the beginning had covered this, but I'll take a look at how it can be made more clear πŸ€“