You are on page 1of 35

CS1010E Tutorial 5

Functions, Random number


Tutorial 5: Functions, Random
Numbers
1. Functions, User-defined Functions
2. Functions as Procedures
3. Lexical Scoping
4. Pass by Value
5. Macros
6. Random Number
Functions
Two types of functions
1. Built-in functions
Functions that are defined and implemented by the
system. Some functions are defined inside a
library.
Example: printf(), scanf(), pow(), fabs(), etc.

2. User-defined functions (or programmer-defined)


Functions that are defined and implemented inside
the program
User-defined Functions
Program syntax with user defined functions

<return_type><function_id>(<input_type 1> <input_id 1>,


<input_type 2> <input_id 2>,
<input_type 3> <input_id 3>,
…){
<statement block>
return <return_expression>;
}

The functions may take as many input arguments as we want.


Use comma to separate different input parameters. The type of
each input argument needs to be specified in the function
header.
User-defined Functions
Alternative way to define functions is to use the
prototype. In this case, the function prototype is written
before the main function and the corresponding
function calls.

The function prototype is written almost similarly to the


corresponding function header, but need only to
specify
Function Prototype
The function prototype is written almost similarly to the
corresponding function header, but need only to
specify the parameter type (parameter name is
encouraged but not necessary).

<return_type><function_id>(<input_type 1>,
<input_type 2>,
<input_type 3>,
…);

Keep in mind the semicolon at the end.


Return Statement
Function terminates with a return value to the caller
function.

A function can only return at most one value.

Upon executing the return statement


1. the expression is evaluated to a value
2. the function returns the value to the caller and
terminates
3. the caller function resumes execution with the
value returned
Function call
Once a function is defined and implemented, it can be
called by another function using the syntax.
<function_id>(<exp 1>,<exp 2>,<exp 3>, …)

The number of input expressions has to match the


number of input parameters written in the function
header.

The caller function may only call another function that


is defined before the caller (either fully implemented or
as a prototype).
User-defined Functions - Example
The following function implements the bank compound
interest (see tutorial 2 question 3b) and computes the
final balance at the end of given month.

double computeBalance(double balance, double rate, int month){


int year = m/12;
bal = bal*pow(1.0+rate/100, year);

return bal;
}

// main function begins here


User-defined Functions - Example
Alternative way to write using function prototype

double computeBalance(double balance, double rate, int month);

// main function here

double computeBalance(double balance, double rate, int month){


int year = m/12;
bal = bal*pow(1.0+rate/100, year);

return bal;
}
User-defined Functions - Example
In the main function, read the values from the user and
call the function computeBalance to compute the final
balance.

int main(){
double bal, r;
int m;
scanf(“%lf %lf %d”, &bal, &r, &m);
bal = computeBalance(bal, r, m);
printf(“%.2f”, bal);
return 0;
}
Functions with no inputs
In general, it is possible to write function that takes no
input arguments, although it is very rarely useful.

To write a function that takes no input arguments,


replace the inputs in the function header syntax with
void, or simply leave as blank.

<return_type><function_id> (void)
Functions with no output
C function also allows to return no output argument.
Functions with no output arguments are typically
known as procedures.

Since the function has no output value, replace the


return type in the function header syntax with void

void <function_id> (<inputs>)


Functions as Procedures - Example
The following procedure takes three integer inputs and
print them to the terminal

void printThree(int a, int b, int c){


printf(“%d%d%d\n”, a, b, c);
return;
}
Lexical Scoping
The scope of accessibility of a variable is within a
function in which the variable is declared (includes
function parameters).

Variables declared within a function are local to that


function, they cannot be accessed from any other
functions.

Exceptions are global variables, where the variables


are defined outside any functions and accessible
across all functions.
Lexical Scoping - Example
int square(int y){ square

int x; variables local to square

x = y*y; y

return x; x
}

int main(){ main

int x=10; result; variables local to main

result = square(x); x

return 0; result
}
Lexical Scoping - Example
int square(int y){ square
int x; variables local to square
x = y*y;
y
return x;
} x

x in both functions are different variables


int main(){ main
int x=10; result; variables local to main
result = square(x);
x
return 0;
} result

The return x inside square function returns the value of variable


x inside square function, and not the main function.
Pass by Value
During a function call, each argument expression is
evaluated and a copy of the value is passed to the
function and stored in each input parameter in the
function. This is called pass-by-value.

Thus, whatever changes made into variables inside a


function do not effect any variables outside the
function (in most cases).
Example
Consider the following procedure to swap two integers

void swap(int a, int b){


int temp = a;
a = b;
b = temp;
return;
}
Example
The following main function calls the swap procedure

main
int main(int a, int b){
a 10
int a=10, b=20;
b 20
swap(a,b);
printf(“%d %d”, a,b);
return 0;
}
Example
In the execution, the values from the main function are
passed into the swap function.
main

a 10
int main(int a, int b){
int a=10, b=20; b 20

swap(a,b);
printf(“%d %d”, a,b); swap(10, 20)

return 0;
}
Example
Inside the swap function, a temporary variable is
declared and is initialised to a
main

a 10
void swap(int a, int b){
int temp = a; b 20

a = b;
b = temp; swap(10, 20)

return; a 10
} b 20

temp 10
Example
After executing the statements, the values of a and b
inside the swap functions are changed, but not in the
main
main function.
a 10

void swap(int a, int b){ b 20

int temp = a;
a = b; swap(10, 20)
b = temp; a 20
return;
b 10
}
temp 10
Example
At the return statement, the procedure is terminated
and does not return any value.
main

a 10
void swap(int a, int b){
int temp = a; b 20

a = b;
b = temp; swap(10, 20)

return; a 20
} b 10

temp 10
Example
The values of the variables in the main function remain
unchanged
main

int main(int a, int b){ a 10


int a=10, b=20; b 20
swap(a,b);
printf(“%d %d”, a,b);
return 0;
}

Program output: 10 20
Macros
A simple operation can also be specified by a
preprocessing directive called a macro. Macros are
typically defined before any functions using #define.

#define <macro_id>(<input_id s>)


<macro_expression>

Upon compilation, the macro expression replaces all


references to the macro id in the program.
Macros - Example
The following macros are defined to perform addition
and multiplication of two numbers.
#define ADD(x,y) x+y
#define MUL(x,y) x*y

Upon compilation, the program will replace the


following by
• ADD(2,3) : 2+3 = 5
• MUL(4,6) : 4*6 = 24
• ADD(2,3)*2 : 2+3*2 = 2+6 = 8
• MUL(2+2,3+3) : 2+2*3+3 = 2+6+3 = 11
Macros - Example
Note that in the example, we do not have
(ADD(2,3))*2 = ADD(2,3)*2 and
MUL(4,6) = MUL(2+2,3+3)

This is because upon compilation, the macros only


replaces text; computations only performed upon
execution. The computations are performed in a
different way as in functions because multiplication
has higher precedence than addition.
Macros - Parentheses
In order for macros to behave the same as functions,
we use parentheses for each input parameters in the
macro definition. We also use parentheses for each
time the macro is used in the function.

#define ADD(x,y) (x)+(y)


#define MUL(x,y) (x)*(y)

(ADD(2,3))*2 : ((2)+(3))*2 = 5*2 = 10


(MUL(2+2,3+3)) : ((2+2)*(3+3)) = (4*6) = 24
Random Number
In C, we can generate a random number using the
rand() function from the stdlib.h.

rand()

The function rand() returns a random integer between


0 and RAND_MAX inclusive. Each integer is equally
likely to occur (uniformly distributed).

RAND_MAX is a system dependent integer defined in


stdlib.h library.
Random Number Seeding
To generate different sequences of random values, we
use the srand function, from stdlib.h library.

srand((unsigned int) <int expression>);

The argument of srand function is an unsigned integer,


typically known as the seed value. For each seed
value, rand generates a different sequence of random
numbers.

srand function is called only once in the program


Random Number Seeding
There are two ways of seeding.

1. Time-based seeding
// time(0) gets current time
srand((unsigned int) time(0));

2. Seeding via user input


// User enters a seed value
scanf(“%d”, &seed);
srand((unsigned int) seed);
Generating Specific Random Numbers
Generating a random number over a specified range
involves scaling followed by shifting.

Generating a random integer over a specified range


• {0,1,2,3,4,5,6,7,8,9} : rand()%10
• {-3,-2,-1,0,1,2,3} : rand()%7 – 3
• {a,a+1,a+2,…,b-1,b} : a + rand()%(b-a+1)
In the last example, a and b are declared as integers.
There are b-a+1 possible values that the random
integer can take.
Generating Specific Random Numbers
To generate a random real number, we consider that
0 <= rand()/RAND_MAX <= 1
The ratio rand()/RAND_MAX here is assumed to be
uniformly distributed over the real numbers in the range
[0,1] (though this is not exactly true).

Generating a random real number over a specified range


• [0, 1.0] : 1.0*rand()/RAND_MAX
• [0, b] : b*rand()/RAND_MAX
• [a, b] : a + ((b-a)*rand()/RAND_MAX)
In the last example, a and b are declared as double. [a,b]
contains all real numbers between a and b inclusive