Polymorphic Data Structures in C/Function Invocation
All C programs contain function calls. For example, in the simplest "Hello World" program, one function call is used:
#include <stdio.h>
int main( int argc , char *argv[] ) {
printf( "Hello, world.\n" ) ;
return 0 ;
}
The function printf() takes in the string "Hello, world.\n" as a parameter, and produces the text on the screen as a result.
Simple Parameters
[edit | edit source]When a function is called, memory space is allocated for that function's local variables and the values of the parameters are copied and placed into the function's memory space. This is why C is sometimes referred to as a "call by value" language. A simple way to examine this principle is by using a program called No Swap.
#include <stdio.h>
void noswap( int x , int y ) ;
int main( int argc , char *argv[] ) {
int x , y ;
x = 5 ;
y = 9 ;
printf( "The values of x and y are %d and %d before the function noswap.\n" , x , y ) ;
noswap( x , y ) ;
printf( "The values of x and y are %d and %d after the function noswap.\n" , x , y ) ;
return 0 ;
}
void noswap( int x , int y ) {
int temp ;
temp = x ;
x = y ;
y = temp ;
}
The output of this program would be:
The values of x and y are 5 and 9 before the function noswap.
The values of x and y are 5 and 9 after the function noswap.
The intent of the program is to swap the values of x and y, but clearly this is not the case. This is because the actual variables x and y are not passed to the function noswap(), but rather copies of the variables are made and pushed onto the function's runtime stack. It is possible to manipulate this behavior, along with the return value of a given function, to create the illusion of instantaneous processing. The code below is a simple addition program that demonstrates the ability to add two integers together.
#include <stdio.h>
int add( int x , int y ) ;
int main( int argc , char *argv[] ) {
int x , y ;
printf( "Please enter two integers to be added together: " ) ;
scanf( "%d %d" , &x , &y ) ;
printf( "The sum of %d and %d is %d.\n" , x , y , add( x , y ) ) ;
return 0 ;
}
int add( int x , int y ) {
return ( x + y ) ;
}
Try to edit the add() function to cause it to subtract, multiply, or take the power of the numbers (the most difficult without adding additional C libraries) instead of adding them.
All types in C can be passed by value, including structures, unions, and arrays.
Pointers as Parameters
[edit | edit source]Using pointers as parameters is the only way to modify local variables in functions other than the one that declared it. Using pointers as parameters is a method known as "simulated call by reference". Its usage is fairly straightforward: instead of passing a copy of the value of a variable, the program simply passes a pointer to the actual value in the calling function. Because of this, the variable must be dereferenced in the called function. Let's examine No Swap again, except it will now be known as Swap.
#include <stdio.h>
void swap( int *x , int *y ) ;
int main( int argc , char *argv[] ) {
int x , y ;
x = 5 ;
y = 9 ;
printf( "The values of x and y are %d and %d before the function swap.\n" , x , y ) ;
swap( &x , &y ) ;
printf( "The values of x and y are %d and %d after the function swap.\n" , x , y ) ;
return 0 ;
}
void swap( int *x , int *y ) {
int temp ;
temp = *x ;
*x = *y ;
*y = temp ;
}
The output of this program would be:
The values of x and y are 5 and 9 before the function noswap.
The values of x and y are 9 and 5 after the function noswap.
Notice that when swap() is called, the address-of operator (&) is used. This is because neither x nor y are pointers. Appending a variable name with the address-of operator causes a pointer of the variable to be passed instead of a copy. Since pointers are simply references to the address of a variable, a copy of the pointer is made and passed to the function, which is why this method is only simulated call by reference and not true call by reference.
Arrays as Parameters
[edit | edit source]Arrays are treated differently than other variables. This is because their name (without a subscript [] to denote a specific value) is simply a pointer to the first item in the array. Therefore, A and &A[0] are the same. Additionally, dereferencing as *A would return the value of A[0].
Because of this behavior, it is extremely easy to pass arrays into a function and modify them.
#include <stdio.h>
void array_copy( int *A , int *B ) ;
int main( int argc , char *argv[] ) {
int i ;
int array[5] ;
int other_array[5] ;
printf( "Please enter five numbers, separated by a space: " ) ;
for ( i = 0 ; i < 5 ; i++ ) scanf( "%d" , &array[i] ) ;
for ( i = 0 ; i < 5 ; i++ ) printf( "%d " , array[i] ) ;
printf( "\n" ) ;
array_copy( array , other_array ) ;
for ( i = 0 ; i < 5 ; i++ ) printf( "%d " , other_array[i] ) ;
printf( "\n" ) ;
return 0 ;
}
void array_copy( int *A , int *B ) {
int i ;
for ( i = 0 ; i < 5 ; i++ ) B[i] = A[i] ;
}
Notice how the output is the same on both lines, even though the address-of operator was not used when array_copy() was called. This is because array bases are already pointers.