We use functions to encapsulate functionality and reuse code. Functions also help us to organize code otherwise every program would be all code under main. A function has a name and may have a return value and parameters .
Ex:
int square( int input )
This function takes an integer as an argument and returns an integer .
Ex:
void method1()
The above function does not return anything indicated by the type "void" and does not take any parameters.
A function must have a definition or a declaration before it can be used. Compilation in a file starts from top to bottom.
File: "function1.c"
#include <stdio.h>
void function1() ;
int main()
{
function1() ;
return( 0 ) ;
}
void function1()
{
printf( "Inside function1.\n" ) ;
}
A program can be run by executing a file such as:
./a.out
The operating system will allocate some area in the RAM for the program to be run. The code of the exe ( machine language instructions ) will occupy some space and 2 sections in the RAM will be reserved ; the stack and the heap.
When a program is run the CPU will fetch an instruction from the RAM and process it and then fetch another instruction from the RAM and process it . Complications arise when there is a function to be called.
Assume the following are machine language instructions loaded in the RAM .
int sum( int x1 , int x2 ) //A
return ( x1 + x2 ) //B
int main()
int result ; //C
result = sum( 4 + 6 ) ; //D
Assume the current instruction is at "C". Now we need to execute the function "sum" but the "sum" is another section of the code. Somehow we need to tell that function that once we are done we need to come back to the main function. So we store this location on the stack.
Stack
---------
//D Store this location
Now we also need to pass the values 4 and 6 to the function . So let's store those also in the stack.
Stack
---------
6
4
//D Store this location
Now we tell the CPU that the next instruction is A and we store 4 and 6 on the stack. Now the CPU starts executing the code at the location "sum" and the sum function grabs the numbers 4 and 6 and has the result 10 that it needs to give back to where the function was called in the "main" function. How does it do that ? Again it puts it on the stack:
Stack
---------
10
It uses the //D location and control is transferred to the main function where the code picks up the result 10 from the stack and and assigns it to the variable "result" . The area for storing this information for a particular function is called a stack frame. Local variables are also created and stored on the stack.
Ex:
void function1()
{
int x1 ;
int x2 ;
int x3 ;
}
Stack
---------
x3
x2
x1
The requirement is that the size of the variables must be known at compile time of the variables to be allocated on the stack.
The "heap" is used to store memory that has been created dynamically when the program is run. The size of the memory can be dynamic. The "malloc" function can be used to allocate dynamic memory .
"malloc"
Memory allocated in any other way will be allocated on the stack.
A program is allocated a certain amount of stack memory. It is possible to run out of stack space. The following program shows how once function calls itself again and again without stopping leading to a crash. A function that calls itself is a recursive function.
File: "stack1.c"
#include <stdio.h>
void function1()
{
int x1[100] ;
function1() ;
}
int main()
{
function1() ;
return( 0 ) ;
}
Output:
Segmentation fault (core dumped)
We have been using "printf" in our programs. The function "printf" is part of the standard library and the we can safely assume that all "C" compilers will have this function. Let us see another example of a standard library function.
File: "sq1.c"
#include <stdio.h>
#include <math.h>
int main( )
{
/* Define temporary variables */
double value;
double result;
/* Assign the value we will find the sqrt of */
printf( "Print a number:" ) ;
scanf( " %lf" , &value ) ;
/* Calculate the square root of value */
result = sqrt(value);
/* Display the result of the calculation */
printf("The square root of %.2f is %.2f\n", value, result);
return 0;
}
Output:
Print a number:34
The square root of 34.00 is 5.83
File: "call1.c"
#include <stdio.h>
#include <math.h>
void changeValue( int input )
{
input = 100 ;
}
int main()
{
int x1 ;
printf( "Enter a number:" ) ;
scanf( "%d" , &x1 ) ;
changeValue( x1 ) ;
printf( "The value of x1 is %d\n" , x1 ) ;
return 0;
}
Output:
Enter a number:3
The value of x1 is 3
When we call the function "changeValue" in main we are not passing the variable "x1" but instead passing the value of "x1" which is say 3 in the above example. Control now moves to the function "changeValue" withe the parameter "input:" which is a local variable to the function and has scope that lasts for the duration of the function. This parameter is assigned the value of 3 and then the value changed to 100 inside the function. The function now ends and the variable "input" goes out of scope. The variable "x1" has not been changed in any way by the function "changeValue" . All the function calls in "C" are pass by value as compared to pass by reference. In pass by reference it is possible to pass a variable itself and the function can change the variable. This is possible to do in "C" using the concept of pointers even though the ass is still by value but the function can change the original value.
Following program shows how the storage specifier works.
File: "storage1.c"
#include <stdio.h>
#include <math.h>
static int staticVar ;
int main()
{
//auto not really needed
auto int x1 ;
//hint to the compiler to store it in the CPU
//register
register int x2 ;
return 0;
}
The static in the above is stating that the variable is global but cannot be used in other files. Usually a variable can be used in another file with the "extern" statement. The "gcc" compiler may not give an error and automatically remove the "static" keyword but that is the intent behind the "static" global variable.
File: "scope1.c"
#include <stdio.h>
void useLocal( void ); /* function prototype */
void useStaticLocal( void ); /* function prototype */
void useGlobal( void ); /* function prototype */
int x = 1 ;
/* function main begins program execution */
int main( void )
{
int x = 5; /* local variable to main */
printf("local x in outer scope of main is %d\n", x );
{ /* start new scope */
int x = 7; /* local variable to new scope */
printf( "local x in inner scope of main is %d\n", x );
} /* end new scope */ 166 Chapter 5 C Functions
useLocal(); /* useLocal has automatic local x */
useStaticLocal(); /* useStaticLocal has static local x */
useGlobal(); /* useGlobal uses global x */
useLocal(); /* useLocal reinitializes automatic local x */
useStaticLocal(); /* static local x retains its prior value */
useGlobal(); /* global x also retains its value */
printf( "\nlocal x in main is %d\n", x );
return 0; /* indicates successful termination */
} /* end main */
/* useLocal reinitializes local variable x during each call */
void useLocal( void )
{
printf( "\nlocal x in useLocal is %d after entering useLocal\n", x );
x++;
printf( "local x in useLocal is %d before exiting useLocal\n", x );
} /* end function useLocal */
/* useStaticLocal initializes static local variable x only the first time
the function is called; value of x is saved between calls to this
function */
void useStaticLocal( void )
{
printf( "\nlocal static x is %d on entering useStaticLocal\n", x );
x++;
printf( "local static x is %d on exiting useStaticLocal\n", x );
} /* end function useStaticLocal */
/* function useGlobal modifies global variable x during each call */
void useGlobal( void )
{
printf( "\nglobal x is %d on entering useGlobal\n", x );
x *= 10;
printf( "global x is %d on exiting useGlobal\n", x );
} /* end function useGlobal */
Output:
local x in outer scope of main is 5
local x in inner scope of main is 7
local x in useLocal is 1 after entering useLocal
local x in useLocal is 2 before exiting useLocal
local static x is 2 on entering useStaticLocal
local static x is 3 on exiting useStaticLocal
global x is 3 on entering useGlobal
global x is 30 on exiting useGlobal
local x in useLocal is 30 after entering useLocal
local x in useLocal is 31 before exiting useLocal
local static x is 31 on entering useStaticLocal
local static x is 32 on exiting useStaticLocal
global x is 32 on entering useGlobal
global x is 320 on exiting useGlobal
local x in main is 5
Recursion is the ability to call a function within the function. Many problems can be solved in an elegant manner using recursion. A recursive program usually breaks down the original problem into a smaller problem and has an end condition also called the base condition/case . This is necessary otherwise the function can repeat for ever.
Let us revisit the factorial problem.
File: "fact1.c"
#include <stdio.h>
int factorial ( int x1 )
{
int result = 1 ;
int i1 ;
for( i1 =2 ; i1 <= x1 ; i1++ )
{
result *= i1 ;
}
return ( result ) ;
}
int main( void )
{
int input ;
printf( "Enter a number:" ) ;
scanf( "%d" , &input ) ;
printf( "Factorial of %d is %d\n" , input , factorial(input ) ) ;
}
Output:
Enter a number:3
Factorial of 3 is 6
Converting the above program to use recursion instead.
File: "fact2.c"
#include <stdio.h>
int factorial ( int x1 )
{
if ( x1 == 1 )
return ( 1 ) ;
return ( x1 * factorial(x1-1) ) ;
}
int main( void )
{
int input ;
printf( "Enter a number:" ) ;
scanf( "%d" , &input ) ;
printf( "Factorial of %d is %d\n" , input , factorial(input ) ) ;
}
Output:
Enter a number:3
Factorial of 3 is 6
The first version "fact1.c" was written using the iterative approach and the second using the recursive approach. The base condition is for the case of the input being 1 in which case we can return 1 without doing a recursive call.
Towers of Hanoi
Hanoi Towers
https://www.geeksforgeeks.org/c-program-for-tower-of-hanoi/
File: "tower1.c"
#include <stdio.h>
// C recursive function to solve tower of hanoi puzzle
void towerOfHanoi(int n1, char from_rod, char to_rod, char aux_rod)
{
if (n1 == 1)
{
printf("\n Move disk 1 from rod %c to rod %c", from_rod, to_rod);
return;
}
towerOfHanoi(n1-1, from_rod, aux_rod, to_rod);
printf("\n Move disk %d from rod %c to rod %c", n1, from_rod, to_rod);
towerOfHanoi(n1-1, aux_rod, to_rod, from_rod);
}
int main()
{
int n1 = 3; // Number of disks
towerOfHanoi(n1, 'A', 'C', 'B'); // A, B and C are names of rods
return 0;
}
We can also pass in the intermediate result in the function in some cases. Let's take a look at the variation of the Factorial program.
File: "fact1.c"
#include <stdio.h>
int factorial ( int x1 , int result )
{
if ( x1 == 1 )
return ( result ) ;
return ( factorial( x1-1 , x1 * result) ) ;
}
int main( void )
{
int input ;
printf( "Enter a number:" ) ;
scanf( "%d" , &input ) ;
printf( "Factorial of %d is %d\n" , input , factorial(input , 1) ) ;
}
We are using a second parameter to store the intermediate result and return is when the end condition is reached. This technique is useful in some cases.
1)
Write a function "isPrimeFunc" that takes a single integer and does not return anything . The function will
print if the number is prime or not. Take the relevant code out of the below program and place it in the function.
File: "prime1.c"
#include <stdio.h>
#include <math.h>
void sPrimeFunc( int x1 )
{
}
int main()
{
int isPrime ;
int input ;
int i1;
int limit ;
printf( "Enter a number:" ) ;
scanf( "%d" , &input ) ;
//Write code
isPrimeFunc( input ) ;
//Replace the below code
isPrime = 1 ;
limit = sqrt( input ) + 1 ;
for( i1 = 2 ; i1<= limit ; i1++ )
{
if ( input % i1 == 0 )
{
isPrime = 0 ;
break ;
}
} //for
if ( isPrime == 1 )
printf( "The nubmer is prime\n" ) ;
else
printf( "The nubmer is not prime\n" ) ;
return 0;
}
2)
Fill in the iterative and recursive function code for the below program.
A Fibonacci series is the series with the first 2 numbers being 0 and 1 and then the next number is the sum of the previous 2 .
0 , 1 , 1 , 2, 3, 5, 8
The 3rd Fibonacci number is 1 and the 4th Fibonacci number is 2 and so on.
#include <stdio.h>
//-------------------------------------------
int iterative ( int x1 )
{
int i1 ;
int f1 = 0 ;
int f2 = 1 ;
int temp ;
if ( x1 == 1 )
return ( 0 ) ;
if ( x1 == 2 )
return ( 1 ) ;
//Complete the code
}
//-------------------------------------------
int recursive( int x1 )
{
if ( x1 == 1 )
return ( 0 ) ;
if ( x1 == 2 )
return ( 1 ) ;
//Complete the code
}
//-------------------------------------------
int main( void )
{
int input ;
printf( "Enter a number:" ) ;
scanf( "%d" , &input ) ;
printf( "%dth Fibonacci is %d\n" , input , iterative(input ) ) ;
printf( "%dth Fibonacci is %d\n" , input , recursive(input ) ) ;
}
3)
Fill in the below code.
File: "power1.c"
#include <stdio.h>
int findBaseToPower( int base, int power )
{
if ( power == 1 )
return ( base ) ;
if ( power == 0 )
return ( 1 ) ;
//Complete the code
}
//-------------------------------------------
int main( void )
{
int base ;
int power ;
printf( "Enter the base:" ) ;
scanf( "%d" , &base ) ;
printf( "Enter the power:" ) ;
scanf( "%d" , &power ) ;
printf( "Base %d to the power %d is %d\n" , base ,
power, findBaseToPower(base, power ) ) ;
}
1)
File: "prime1a.c"
#include <stdio.h>
#include <math.h>
void isPrimeFunc( int param1 )
{
int check ;
int i1;
int limit ;
//Write code
check = 1 ;
limit = sqrt( param1 ) + 1 ;
for( i1 = 2 ; i1<= limit ; i1++ )
{
if ( param1 % i1 == 0 )
{
check = 0 ;
break ;
}
} //for
if ( check == 1 )
printf( "The nubmer is prime\n" ) ;
else
printf( "The nubmer is not prime\n" ) ;
}
//------------------------------------------------
int main()
{
int input ;
printf( "Enter a number:" ) ;
scanf( "%d" , &input ) ;
isPrimeFunc( input ) ;
return 0;
}
2)
#include <stdio.h>
//-------------------------------------------
int iterative ( int x1 )
{
int i1 ;
int f1 = 0 ;
int f2 = 1 ;
int temp ;
if ( x1 == 1 )
return ( 0 ) ;
if ( x1 == 2 )
return ( 1 ) ;
for( i1 = 2 ; i1 < x1 ; i1++ )
{
temp = f1 ;
f1 = f2 ;
f2 = temp + f1 ;
}
return ( f2 ) ;
}
//-------------------------------------------
int recursive( int x1 )
{
if ( x1 == 1 )
return ( 0 ) ;
if ( x1 == 2 )
return ( 1 ) ;
return( recursive( x1-1 ) + recursive( x1-2 ) ) ;
}
//-------------------------------------------
int main( void )
{
int input ;
printf( "Enter a number:" ) ;
scanf( "%d" , &input ) ;
printf( "%dth Fibonacci is %d\n" , input , iterative(input ) ) ;
printf( "%dth Fibonacci is %d\n" , input , recursive(input ) ) ;
}
3)
#include <stdio.h>
//-------------------------------------------
int findBaseToPower( int base, int power )
{
if ( power == 1 )
return ( base ) ;
if ( power == 0 )
return ( 1 ) ;
//Complete the code
return ( base * findBaseToPower(base, power-1 ) ) ;
}
//-------------------------------------------
int main( void )
{
int base ;
int power ;
printf( "Enter the base:" ) ;
scanf( "%d" , &base ) ;
printf( "Enter the power:" ) ;
scanf( "%d" , &power ) ;
printf( "Base %d to the power %d is %d\n" , base ,
power, findBaseToPower(base, power ) ) ;
}