C programming data structure and algorithms, Study notes of Data Structures and Algorithms

This is PDF for data structure and algorithms

Typology: Study notes

2017/2018

Uploaded on 09/06/2018

Korekiye
Korekiye 🇳🇬

1 document

1 / 40

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
FUNCTIONS
A function is a block of code meant to perform a defined set of tasks. In many cases
these tasks are meant to be repeated several times in a program.
A function has two parts and these are:
1. A head also known as its prototype
2. A body
The head is made up of
1. The type of value (data type e.g. int) the function is to return when it completes
its task. If the function doesn’t return any data type, the word void is used as
return type.
2. The name of the function (a valid identifier)
3. List of parameters enclosed in brackets (comma-separated list of data type-valid
identifier pairs). If the function does not require a parameter, the brackets are
kept empty.
The name of the function and its parameter list put together, makes up what is called
the signature of the function.
The body (definition) of a function is a list of programming statements enclosed in
braces immediately after the head of the function
The structure of functions are as given below:
1. For a function that takes parameters
type name (type id, type id, …, type id)
{
//Body of function
}
2. For a function that doesn’t take a parameter
type name ()
{
//Body of function
}
The codes for most of the common programming tasks one can think of, have already being
provided in header files that make up the C library. As a result of this, it is not
necessary for a programmer to write his or her own codes for these tasks (reinventing
the wheel).
In order to use any of these functions, the header in which it has been defined must be
specified. This is done by using the format #include <header_name.h>, which I believe is
a familiar programming statement by now.
SOME LIBRARY FUNCTIONS
Popular mathematical functions are provided in the header math.h. Some of these functions
are given below:
S/N
Function
Prototype
Description
Found in math.h
1
asin()
double asin(double x)
Returns the value of sin-1(x) which is an angle
in radians
2
acos()
double acos(double x)
Returns cos-1(x) which is also an angle in
radians
3
atan()
double atan(double x)
Returns tan-1(x) in radians as well
4
sin()
double sin(double x)
Returns the value of sine(x) which is a ratio
(no unit)
5
cos()
double cos(double x)
Returns the value of cosine(x) which is also a
ratio
6
tan()
double tan(double x)
Returns the value of the tangent of x (also a
ratio)
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28

Partial preview of the text

Download C programming data structure and algorithms and more Study notes Data Structures and Algorithms in PDF only on Docsity!

FUNCTIONS

A function is a block of code meant to perform a defined set of tasks. In many cases

these tasks are meant to be repeated several times in a program.

A function has two parts and these are:

1. A head also known as its prototype

2. A body

The head is made up of

1. The type of value (data type e.g. int) the function is to return when it completes

its task. If the function doesn’t return any data type, the word void is used as

return type.

2. The name of the function (a valid identifier)

3. List of parameters enclosed in brackets (comma-separated list of data type-valid

identifier pairs). If the function does not require a parameter, the brackets are

kept empty.

The name of the function and its parameter list put together, makes up what is called

the signature of the function.

The body (definition) of a function is a list of programming statements enclosed in

braces immediately after the head of the function

The structure of functions are as given below:

1. For a function that takes parameters

type name (type id, type id, …, type id)

//Body of function

2. For a function that doesn’t take a parameter

type name ()

//Body of function

The codes for most of the common programming tasks one can think of, have already being

provided in header files that make up the C library. As a result of this, it is not

necessary for a programmer to write his or her own codes for these tasks (reinventing

the wheel).

In order to use any of these functions, the header in which it has been defined must be

specified. This is done by using the format #include <header_name.h> , which I believe is

a familiar programming statement by now.

SOME LIBRARY FUNCTIONS

Popular mathematical functions are provided in the header math.h. Some of these functions

are given below:

S/N Function Prototype Description

Found in math.h

1 asin() double asin(double x) Returns the value of sin-^1 (x) which is an angle

in radians

2 acos() double acos(double x) Returns cos-^1 (x) which is also an angle in

radians

3 atan() double atan(double x) Returns tan-^1 (x) in radians as well

4 sin() double sin(double x) Returns the value of sine(x) which is a ratio

(no unit)

5 cos() double cos(double x) Returns the value of cosine(x) which is also a

ratio

6 tan() double tan(double x) Returns the value of the tangent of x (also a

ratio)

7 sinh() double sinh(double x) sinh(x) returns the value of the hyperbolic sine

of x

8 cosh() double cosh(double x) cosh(x) returns the value of the hyperbolic

cosine of x

9 tanh() double tanh(double x) cosh(x) returns the value of the hyperbolic

tangent of x

From stdlib.h

10 abs() int abs(int x) abs(x) returns the absolute value of x

11 ceil() double ceil(double x) ceil(x) = ⌈𝑥⌉ represents the nearest whole

number which is not less than x e.g. ceil(2.5)

= 3.0, ceil(3.0) = 3.0, ceil(-2.3) = - 2.

12 floor() double floor(double x) floor(x) = ⌊𝑥⌋ represents the nearest whole

number which is not greater than x e.g.

floor(2.5) = 2, floor(3.0) = 3.0, floor(-2.3) =

  • 3

13 pow() double pow(double x, double y) Returns the value of xy

14 sqrt() double sqrt(double x) Returns the value of √𝑥

15 cbrt() double cbrt(double x) Returns the value of 3 √𝑥

Calling a function requires providing its name and arguments (representing parameters in

the prototype), if that is necessary. The number of arguments provided must match the

number of parameters, both in order and data type. For example pow(3.0, 2.0), cbrt(27.0),

e.t.c. This is normally done from the main function or another function.

Example

#include <stdio.h> #include <math.h> #include <stdlib.h> int main () { double a = cbrt ( 27.0 ); double b = ceil (- 1.0004 ); double c = floor (- 1.004 ); printf ( "cbrt(27.0) = %lf\n" , a ); printf ( "ceil(-1.0004) = %lf\n" , b ); printf ( "floor(-1.004) = %lf\n" , c ); return 0 ; } Output cbrt(27.0) = 3. ceil(-1.0004) = -1. floor(-1.004) = -2. DEVELOPING A FUNCTION

In most cases a function take some values, does some computation with these values in

the body and return the result of the computation afterwards. The ingredients needed to

develop a function in order of importance are:

1. Parameters which represent the input values needed in the function. If the function

requires none, it the brackets are kept empty.

2. The return type i.e. the type of value to be returned after the computation in the

body. In the body of the function, the return keyword is used to send back the

computed result. The format is return value;.

3. The name of the function

Example

Develop a function that computes that computes the volume of a cylinder.

Paramters : radius (r), height (h) all of type double.

POSITIONING A DEVELOPED FUNCTION IN A PROGRAM

So far the task has been developing functions in isolation. The time has come to develop and use one in

an actual program. There are two approaches to this.

1. Placing the functions before the main function in a program

2. Placing the functions to after the main function.

Using the first approach is my personal favorite, because as will be shown below, it gives a program with

fewer lines of code. This is because the second approach requires placing the prototype of the functions

before the main function, after which the whole function is the then provided under the main function.

Example

The program below is developed to use the function created above.

Method One

#include <stdio.h> #include <math.h> int main () { // input values double a = 5.0 ; double b = 4.0 ; double c = 6.0 ; // compute s double s = ( a + b + c )/ 2 ; // compute area double area = sqrt ( s ( s - a )( s - b )(* s - c )); // display area printf ( "Area = %lf\n" , area ); return 0; } Method Two #include <stdio.h> #include <math.h> // prototype of function double triangleArea ( double a , double b , double c ); int main () { double area = triangleArea ( 4.0 , 5.0 , 6.0 ); printf ( "Area = %lf\n" , area ); return 0; } // function defined under the main function double triangleArea ( double a , double b , double c ) { // compute s double s = ( a + b + c )/ 2 ; // compute area double area = sqrt ( s ( s - a )( s - b )(* s - c )); // Return computed value return area ; }

BENEFITS OF USING FUNCTIONS

1. Smaller source files: Using a function provides a way of representing several lines of code with just

a line of code, thus reducing the size of the source file. Instead of repeating these tasks at all

points where these tasks are to be performed.

  1. Ease of maintenance: if there is the need to make a modification to how the task of a function is

to be carried out, it will require just making the change in one spot, which is in the code implementing

the function, instead of several places if a function is not used.

EXERCISES

1. Write a function that will calculate the nth root of fractional number x i.e. √𝑥

𝑛

2. Write a program that will compute and display the roots (real or complex) of a quadratic equation.

3. Derive a function called quadRoot from the program in (2)

Hint : Make the return type void, because the result of the program may be more than one value.

Just focus on making the function display the roots.

RECURSION

This is a situation where a function invokes itself with a modification to its original argument. This recalling

and modification of argument continues until a base argument obtained, at which point the self-recalling

activity stops.

This process in which a function calls itself in trying to compute its output is called recursion. Among the

many computations available that illustrate the concept of recursion, attention will be given to two.

Factorial of a Number

It can be expressed that

6! = 6 × 5 × 4 × 3 × 2 × 1

5! = 5 × 4 × 3 × 2 × 1

4! = 4 × 3 × 2 × 1

This implies that

6! = 6 × 5!

5! = 5 × 4!

Going by this, it can therefore be said that, the general form of calculating the factorial of a number n can

be written as:

n! = n × (n-1)!

However it is important to state that, 1! and 0! will give a value of 1, thus making 1 the base argument.

This implies that the argument used in the recursive function (factorial) will continue to reduce until it gets

to 1 where recursion stops. With these facts established, the function for computing the factorial of a number

can be written as follows:

int factorial(int n)

if(n == 1 || n == 0)

return 1;

else

return n*factorial(n -1);//function calling itself

F1 = 1

F2 = 1 + 0 = 1

F3 = 1 + 1 = 2

F4 = 1 + 2 = 3

F5 = 2 + 3 = 5

The generalized expression for all terms from the third is given as:

Fn = Fn-2 + Fn-

From the general expression, the function to display the nth term of the Fibonacci series, is as given below:

int fibo(int n)

if(n == 0 || n == 1)

return n;

else

return fibo(n – 1) + fibo(n – 2);

Example

Write a program to display the first 10 terms of the Fibonacci series, using the format below:

Solution #include <stdio.h> int fib ( int n ) { if( n == 0 || n == 1 ) return n ; else return fib ( n - 1 ) + fib ( n - 2 ); } int main () { int i ; for( i = 0 ; i <= 10 ; i ++) { printf ( "F(%2d) = %d\n" , i , fib ( i )); } return 0 ; } RANDOM NUMBER GENERATION

The function rand() which is found the header stdlib.h is used for generating random numbers in C

programs. The function generates a random number from 0 to RAND_MAX, which is a constant value defined

in the header stdlib.h. The value of RAND_MAX is at least 32767.

A program using rand() to generate random numbers will always generate exactly the same set of random

numbers. This is the case even when the program is closed and reopened for execution.

Example

#include <stdio.h> #include <stdlib.h> int main () { int i ; //generate 4 random numbers for( i = 0 ; i < 4 ; i ++) printf ( "%d\n" , rand ()); return 0 ; }

1 st^ Run

2 nd^ Run

In order to prevent this from happening the function srand() is used. It takes positive number (unsigned

number which is the same as an unsigned int) as argument. This number is called a seed. When this

function is used, the random numbers generated change as the seed is changed.

Note: placeholder or format specifier for unsigned int or simply unsigned is u.

Example

#include <stdio.h> #include <stdlib.h> int main () { int i , j , seed ; srand ( time (NULL)); for( i = 0 ; i < 4 ; i ++) { printf ( "Enter a seed: " ); scanf ( "%u" , & seed ); srand ( seed ); for( j = 0 ; j < 4 ; j ++) printf ( "%d\n" , rand ()); printf ( "\n\n" ); } return 0 ; }

1 st^ Run

Enter a seed: 2

2 nd^ Run

If there is an intention to reduce the maximum number that can be generated to say n, then using

rand()%(n+1) will do the job. With that said, If this function is to be used for generating the numbers

on the face of a die, it will require getting numbers from 0 to 5 using rand()%6. In order to get the

value from 0 – 5 to 1 – 6, the formula will become 1 + rand()%6.

Example

#include <stdio.h> #include <stdlib.h> int main () { int i , j ; srand ( time (NULL)); for( j = 0 ; j < 8 ; j ++) printf ( "%d\n" , 1 + rand ()% 6 ); return 0 ; }

Output

Note: It is important to state that the function and string argument system(“cls”) can be used to clear

the output of a screen while a program is still in execution.

Example

#include <stdio.h> #include <stdlib.h> int main () { int i , j , seed ; for( i = 0 ; i < 4 ; i ++) { srand ( seed ); for( j = 0 ; j < 4 ; j ++) printf ( "Seed: %u\tNumber: %d\n" , seed , rand ()); } system ( "cls" ); printf ( "Output has been cleared\n" ); return 0 ; }

Output

Output has been cleared.

ARRAYS

It is a cluster of variables of the same type. The following are the facts to note about arrays:

1. Each variable in the cluster is called an element.

2. The number of variables in the arrays is called the size/dimension/length of the array.

3. The cluster of variables share a single name.

4. The position of a variable in the cluster is represented by a non-negative whole number called its

index.

5. The index of the first element is 0, while that of the last is size – 1.

Arrays are used when there is the need to work with a lot of variables of the same type. Using arrays

makes the process a lot simpler than declaring each variable separately.

CREATING ARRAYS

The syntax creating an array is as given below:

Method 1 :

type name[size]; e.g int scores[30];

In most cases, the size of the array is provided as a constant declared before any function. This is done

by using the format: #define NAME value e.g. #define SIZE 10

This is placed immediately after all headers have been introduced.

Method 2 (initialization method):

type name[] = {value, value, …, value}; e.g. int ages[] = {6, 15, 89, 7};.

The size of the array is equal to the number of values provided for initialization. That of the array (ages)

in the example is 4.

REFERENCING ELEMENTS IN AN ARRAY

In order to display the value of an element, or assign to it a value, or use in its value in some computational

process, it has to be referenced (get a hold of it). Every element in an array is referenced using the form:

name[index] e.g. ages[0].

In most cases, all the elements of an array are accessed together, one after the other. The most efficient

way of doing this is using a loop (since index values of successive elements differ by 1) and the people’s

favorite for this, is the for-loop. The elements are used in the body of the loop. One element per iteration

of the loop. The loop format is

for(index = 0; index < size; index++)

// array[index] is used to reference an element

DISPLAYING THE VALUES IN AN ARRAY

An array created with its size specified explicitly is uninitialized and an as such its elements contain values

that can’t be predicted. The example below illustrates this concept and also provides a means of appreciating

the use of the for-loop for accessing array elements.

Access with loop

#include <stdio.h> #include <stdlib.h> int main () { int score [ 6 ]; int i ; for( i = 0 ; i < 6 ; i ++) { printf ( "%d\n" , score [ i ]);

printf ( "%d\n" , scores [ index ]); } // display content of ages printf ( "\n\nContent of the ages-array\n" ); for( index = 0 ; index < 7 ; index ++) { printf ( "%d\n" , ages [ index ]); } return 0 ; }

Output

Content of the scores-array

Content of the ages-array

It is important to state at this juncture that if the size of an array is specified in a variable

ENTERING DATA INTO THE ELEMENTS

The pattern is not different from what is done with an ordinary variable. Doing this requires providing the

format specifier as well as the address of the element by using the Amper’s AND symbol (&). The format

for an int array is scanf(“%d”, &name[index]);

Code

#include <stdio.h> #include <stdlib.h> int main () { int scores [ 4 ] = { 45 }; // providing just a value int i ; // index variable // enter values into array printf ( "Enter 4 numbers\n" ); for( i = 0 ; i < 4 ; i ++) { scanf ( "%d" , & scores [ i ]); } // print values that have been entered printf ( "\n\nValues entered in order of index are\n" ); for( i = 0 ; i < 4 ; i ++) { printf ( "%Index %d: %d\n" , i , scores [ i ]); } return 0 ; }

Output

Enter 4 numbers

Values entered in order of index are

Index 0: 45

Index 1: 78

Index 2: 100

Index 3: 12

MULTI-DIMENSIONAL ARRAYS

All the arrays that have been discussed and used in examples thus far, are termed one-dimensional arrays.

It is possible to create multi-dimensional arrays. This is done by simply providing the sizes matching the

needed dimension of the array. The format is as shown below:

type name[size][size]; for a 2-dimensional array e.g. int scores[6][7];

type name[size][size][size]; for a 3-dimensional array e.g. int scores[7][8][4];

When accessing the elements in a multidimensional array the number for-loops nested is equal to the

dimension e.g. a 2-dimensional array requires 2 for-loops. An element in a multidimensional array is referenced

by using the name all it index values (which match the dimension of the array) e.g. score[0][3] for a 2-

dimensional array and scores[0][0][7] for a 3-dimensional array. The programs below illustrate how

multidimensional arrays are used.

Code

#include <stdio.h> int main () { int i , j , k ; // for index values // 2 - dimensional array declared and intitialized int array1 [ 4 ][ 5 ] = { 45 }; // 3 - dimensional array declared and initialized int array2 [ 3 ][ 5 ][ 4 ] = { 56 }; // display the content of array for( i = 0 ; i < 4 ; i ++) { for( j = 0 ; j < 5 ; j ++) { printf ( "%2d" , array1 [ i ][ j ]); } printf ( "\n" ); } printf ( "\n\n" ); // display the content of array for( i = 0 ; i < 3 ; i ++) { printf ( "\ni = %d\n" , i ); for( j = 0 ; j < 5 ; j ++) { for( k = 0 ; k < 4 ; k ++) { printf ( "%2d" , array2 [ i ][ j ][ k ]); } printf ( "\n" ); }

return 0 ; }

Output

Two-Dimensional Array

#include <stdio.h> void display ( int array [][ 3 ], int size ) { int i , j ; for( i = 0 ; i < size ; i ++) { for( j = 0 ; j < 3 ; j ++) printf ( "%d\t" , array [ i ][ j ]); printf ( "\n\n" ); } } int main () { int array [ 4 ][ 3 ] = { 4 , 7 , 11 }; display ( array , 4 ); return 0 ; }

Output

USING SIZEOF FUNCTION WITH ARRAYS

It is important to note that using the sizeof function with the name of an array as its argument returns

the total size (in bytes) of an array. If this value is divided by the size of the data type or the size of

one of its element, the dimension of the array will be obtained.

i.e. dimension = sizeof(array)/sizeof(array[0])

If the argument is made of just a word, then the brackets won’t be necessary, but if it is composed of

more than one word then the brackets are compulsory.

This shows that:

dimension = sizeof(array)/sizeof(array[0]) = sizeof(array)/sizeof(array[0])

POINTERS

Data is stored in the memory of a computer. Each storage location (normally in bytes) in a computer’s

memory has a unique address. Address values are numeric and they run from 0 to a maximum value

determined by the size of the memory (number of storage locations).

Since address of storage locations in memory are numeric, it is possible to store and treat them like any

other data. A variable occupies several memory locations (bytes) depending on the type of data it is to

hold. A pointer is therefore a variable which stores memory address (address of the first byte occupied) of

a variable. Since a variable contains a specific value while a pointer holds the address of a variable, it is

stated that the name of a variable references a value directly, while a pointer references the same value

indirectly.

DECLARING A POINTER

type *name; e.g. int *numbPtr;

The address of a variable is represented by &name and this address value can be assigned to a pointer.

The asterisk is dropped after declaration when the pointer is to be used.

For example

int var = 10; // variable initialized

int *varPtr; // declare pointer

varPtr = &var; // pointer assigned the address of var

Since a pointer indirectly references the value in a variable, the value in the variable can be accessed

through a pointer by placing an asterisk (indirection operator) next to the pointer i.e. *pointer. When

displaying the address value in a pointer %p is the format or conversion specifier used to get the address

in hexadecimal form, while %d will display the address in base 10.

& and * are complement operators i.e. each nullifies the effect of the other. For this reason

varPtr = &*varPtr = *&varPtr = &var

The program below illustrates all of the above points.

Code

#include <stdio.h> int main () { int var ; // variable declared var = 10 ; // variable assigned 10 int ***** varPtr ; // pointer to var declared varPtr = & var ; // pointer assigned the address of var printf ( "Value through direct access\nvar = %d\n" , var ); printf ( "\nValue through indirect access\nvarPtr = %d\n" , *** varPtr ); printf ( "\nAddress from pointer\nvarPtr = %p\n" , varPtr ); printf ( "\nAdddress from variable\n&var = %p(in base 10: %d)\n" , & var , & var ); printf ( "\n&varPtr = %p\n" , & varPtr ); printf ( "&varPtr = %p\n" , & varPtr ); printf ( "varPtr = %p\n" , varPtr ); printf ( "\n&var = %d\n" *, & var ); printf ( "var = %d\n" , var ); return 0 ; }

Output

Value through direct access

var = 10

printf ( "*voidPtr1 = %d\n" *, ( int ) voidPtr1 ); printf ( "voidPtr2 = %f\n" *, ( float *) voidPtr2 ); return 0 ; }

Output

aPtr = 2686684 (in Hex: 0028FEDC)

bPtr = 2686680 (in Hex: 0028FED8)

voidPtr1 = 0 (in Hex: 00000000)

voidPtr2 = 4201696 (in Hex: 00401CE0)

*aPtr = 9

*bPtr = 10.

*voidPtr1 = 9

*voidPtr2 = 10.

POINTERS AND ARRAYS

The following are important facts to note about the relationship that exist between pointers and arrays:

1. The name of an array without the square brackets and an index value is a pointer to the address

of the first element in the array.

2. Since the variables (elements) of an array are successively positioned in memory, the size of each

variable can be worked out from difference between their addresses.

3. The address of an element in an array can be referenced by using &name[index]

For purposes of illustration the program below is presented.

Code

#include <stdio.h> int main () { int i [ 10 ], n ; float f [ 10 ]; double d [ 10 ]; printf ( "Size of an integer: %dbytes\n" , sizeof( int )); printf ( "Size of a float: %dbytes\n" , sizeof( float )); printf ( "Size of a double: %dbytes\n\n" , sizeof( double )); /* Print the table heading / printf ( "\t\tInteger\t\tFloat\t\tDouble" ); printf ( "\n================================" ); printf ( "=========================" ); / Print the addresses of each array element. */ for( n = 0 ; n < 10 ; n ++) printf ( "\nElement %d:\t%ld\t\t%ld\t\t%ld" , n , & i [ n ], & f [ n ], & d [ n ]); printf ( "\n================================" ); printf ( "=========================\n\n" ); printf ( "i = %ld\t\t&i[0] = %ld\n" , i , & i [ 0 ]); printf ( "f = %ld\t\t&f[0] = %ld\n" , f , & f [ 0 ]); printf ( "d = %ld\t\t&d[0] = %ld\n" , d , & d [ 0 ]); return 0 ; }

Output

Size of an integer: 4bytes

Size of a float: 4bytes

Size of a double: 8bytes

Integer Float Double

Element 0: 2686660 2686620 2686536

Element 1: 2686664 2686624 2686544

Element 2: 2686668 2686628 2686552

Element 3: 2686672 2686632 2686560

Element 4: 2686676 2686636 2686568

Element 5: 2686680 2686640 2686576

Element 6: 2686684 2686644 2686584

Element 7: 2686688 2686648 2686592

Element 8: 2686692 2686652 2686600

Element 9: 2686696 2686656 2686608

i = 2686660 &i[0] = 2686660

f = 2686620 &f[0] = 2686620

d = 2686536 &d[0] = 2686536

Notice that the difference between successive addresses corresponds to size of the various data types. The

size of a data type as has been shown in the program, is obtainable with the function sizeof(). In

addition, it has been shown that the name of the array and the address of the first element are one and

the same.

POINTER ARITHMETIC

If a pointer is incremented or decremented by a value, it is done by the size of the data type.

Code

#include <stdio.h> int main () { int i ; int ***** iPtr = & i ; printf ( "iPtr: %ld\n" , iPtr ); iPtr ++; // increase by 4 bytes printf ( "iPtr++: %ld\n" , iPtr ); iPtr += 2 ; // increase by 8 bytes (2 x 4) printf ( "iPtr += 2: %ld\n" , iPtr ); iPtr - = 3 ; // decrease by 12 bytes printf ( "iPtr - = 3: %ld\n" , iPtr ); return 0 ; }

Output

iPtr: 2686696

iPtr++: 2686700

iPtr += 2: 2686708

iPtr -= 3: 2686696