Functions

We often write large programs and it is a good idea to split large steps into smaller procedures. These small procedure blocks are known as functions. Functions are often required to do repetitive jobs. We can define a function and call them from anywhere we need. This is a good choice for code reuse and code size optimization.

Arguments

Functions are generally written for a particular operation with one or more inputs. Like we write a function to check if the number is prime or not. Here we write a logic which is not dependent on any specific number but can be used for any positive integers. We reuse this logic by providing an input number. This input is called function argument.

Function call and return

Arguments are small set of variables, temporarily stored in current context of stack. Compiler passes these arguments to calling function by pushing the variables to the stack from right side to left side. Passing variables are similar to coping the variables to a temporary place. Stack grows as compiler pushes more arguments. Finally it pushes the return address and jumps to the function. Now function can do its operation and return from the context. Return statement causes microprocessor to pop the return address from the stack and jumps back to caller. Compiler further shrinks the stack and rewinds to caller context.

Call by value

In call by value mechanism, the called function creates a new set of variables in stack and copies the values of the arguments into them.
Example: Program showing the Call by Value mechanism.

Call by value source code


void swap(int x, int y)
{ 
  int z;
  z = x;
  x = y;
  y = z;
  printf("Swapped values are a = %d and b = %d", x, y);
}

int main (int argc, char *argv[])
{
  int a = 7, b = 4;
  printf("Original values are a = %d and b = %d", a, b);
  swap(a, b);
  printf("The values after swap are a = %d and b = %d", a, b);
}

Output

  Original Values are a = 7 and b = 4
  Swapped values are a = 4 and b = 7
  The values after swap are a = 7 and b = 4

This happens because when function swap() is invoked, the values of a and b gets copied onto x and y. The function actually swaps x and y while the values of the original variables a and b remain intact.

Call by value flow diagram

Here is the flow diagram describing disassembly steps, call stack and argument variables. Calling swap (a, b) can be split into some assembly steps like-

  1. push value of b
  2. push value of a
  3. save return address
  4. call function

Call by value - describing disassembly steps, call stack and argument variables

Here one point to note is x and y are in stack. Value of a and b will be copied to x and y. Inside swap() value of x and y will be interchanged but it will not affect a and b in the main(). Please note a and b are located at the context of main() whereas x and y located at the context of swap(). When swap() function returns, this context of x and y will be lost and it will again come back to the context of a and b.

Call by reference

In call by reference mechanism, instead of passing values to the function being called, references/pointers to the original variables are passed.
Example: Program interchange values of two variables by call by reference mechanism.

Call by reference source code


void swap(int *x, int *y)
{
  int z;
  z = *x;
  *= *y;
  *= z;
  printf("Swapped values are a = %d and b = %d", *x, *y);
}
int main (int argc, char *argv[])
{
  int a = 7, b = 4;
  printf("Original values are a = %d and b = %d", a, b);
  swap(&a, &b);
  printf("The values after swap are a = %d and b = %d", a, b);
}

Output

  Original Values are a = 7 and b = 4
  Swapped values are a = 4 and b = 7
  The values after swap are a = 4 and b = 7

This happens because when function swap() is invoked, it creates a reference for the first incoming integer a in x and the second incoming integer b in y. Hence the values of the original variables are swapped.

Call by reference flow diagram

Here is the flow diagram describing disassembly steps, call stack and argument variables. Calling swap (&a, &b) can be split into some assembly steps like-

  1. push address of b
  2. push address of a
  3. save return address
  4. call function

Call by reference - describing disassembly steps, call stack and argument variables

Here one point to note is x and y are pointers. Address of a and b will be copied to x and y. Inside swap() values of pointers will be interchanged. Dereferencing "x" which is same as accessing "a" and the same is true for y. Dereferencing addresses at x and y is same as accessing a and b accordingly. Thus values of a and b will be interchanged after the return of swap().

Call by reference in C++

C++ compiler can use existing C like call by reference as described above. Additionally C++ developers can write call by reference in C++ conversion with &. We are rewriting our call by reference C code in C++ style. Call by reference in C++ also obeys same principle as explained earlier. Calling the function by reference does not require &. This may look like we are calling by value but C++ compiler looks into the prototype and internally passes reference of the variables.

C ++ Call by reference source code


void swap(int &x, int &y)
{
  int z;
  z = x;
  x = y;
  y = z;
  printf("Swapped values are a = %d and b = %d", *x, *y);
}
int main (int argc, char *argv[])
{
  int a = 7, b = 4;
  printf("Original values are a = %d and b = %d", a, b);
  swap(a, b);
  printf("The values after swap are a = %d and b = %d", a, b);
}

Output

  Original Values are a = 7 and b = 4
  Swapped values are a = 4 and b = 7
  The values after swap are a = 4 and b = 7

About our authors: Team EQA

You have viewed 1 page out of 252. Your C learning is 0.00% complete. Login to check your learning progress.

#