You are on page 1of 161

COURSE OF FUNDAMENTALS OF PROGRAMMING

WITH C LANGUAGE

Hours per week: 5

Instructor: HATANGIMBABAZI Hilaire

E_mail: hatahilaa@gmail.com

Tel: +250 788 432 967


CHAP 1. INTRODUCTION TO C

C is a programming language developed at AT & T’s Bell Laboratories of USA in


1972. It was designed and written by a man named Dennis Ritchie. In the late
seventies C began to replace the more familiar languages of that time like PL/I,
ALGOL, etc. ANSI C standard emerged in the early 1980s, it took several years
for the compiler vendors to release their ANSI C compilers and for them to
become ubiquitous. C was initially designed for programming UNIX operating
system. Now the software tools as well as the C compiler are written in C. Major
parts of popular operating systems like Windows, UNIX, Linux are still written
in C. This is because even today when it comes to performance (speed of
execution) nothing beats C. Moreover, if one is to extend the operating system
to work with new devices, one needs to write device driver programs. These
programs are exclusively written in C. C seems so popular because it is
reliable, simple and easy to use. Often heard today is – “C has been already
superseded by languages like C++, C# and Java.”

1.1 Program

There is a close analogy between learning a language like English and learning
C language. The classical method of learning English is to first learn the
alphabets used in the language, then learn to combine these alphabets to form
words, which in turn are combined to form sentences and sentences are
combined to form paragraphs. Learning C is similar and easier. Instead of
straight- away learning how to write programs, we must first know what
alphabets, numbers and special symbols are used in C, then how using them.
Constants, variables and keywords are constructed, and finally how are these
combined to form an instruction. A group of instructions would be combined
later on to form a program.

So, a computer program is just a collection of the instructions necessary to


solve a specific problem when it is executed by a computer. The basic
operations of a computer system form what is known as the computer’s
instruction set. And the approach or method that is used to solve the problem
is known as an algorithm.
1
A computer program is usually written by a computer programmer and can
be written in either high-level or low-level languages, depending on the task
and the hardware being used.

1.2 Programming language

A programming language is a formal language, which comprises a set of


instructions that produce various kinds of output. Programming languages
consist of instructions for computers and they are used in computer
programming to implement specific algorithms.

Programming languages are divided into two different levels:

1. Low level language


2. High level language

1.2.1 Low-level language

Low level languages are machine level and assembly level languages.

In machine level language computers only understand digital numbers i.e. in


the form of 0 and 1. So, instruction given to the computer is in the form of a
binary digit, which is difficult to implement in binary code. This type of
program is not portable, difficult to maintain and also error prone.

The assembly language is on the other hand modified version of machine level
2
language. Where instructions are given in English like words such as ADD,
SUM, MOV etc. It is easy to write and understand but not understood by the
machine. So the translator used here is assembler to translate into machine
level. Although the language is a bit easier, a programmer has to know low level
details related to low level language. In the assembly level language, the data is
stored in the computer register, which varies for different computers. Hence,
the assembly language is not portable.

1.2.2 High level language

These languages are machine independent, which means they are portable.
Examples of languages in this category are Pascal, Cobol, Fortran, C, Python,
Java, etc.

High level languages are not understood by the machine. So it needs to be


translated into machine level by the translator.

3
1.2.2.1 Translator

A translator is software which is used to translate high level language as well


as low level language into machine level language.

There are three types of translators namely: Compiler, Interpreter and


Assembler.

Compiler and interpreter are used to convert the high-level language into
machine-level language.

The program written in a high-level language is known as a source program


and the corresponding machine-level language program is called an object
program.

Both compiler and interpreter perform the same task but how they work is
different. Compiler reads the program at-a-time and searches the errors and
lists them. If the program is error free then it is converted into an object
program. When program size is large then compiler is preferred. Whereas the
interpreter reads only one line of the source code and converts it to object code.
Interpreter checks errors, statement by statement and hence this process takes
more time.

An assembler translates assembly language into machine code and is


effectively a compiler for the assembly language, but can also be used
interactively like an interpreter.

Assembly language uses words called ‘mnemonics’, such as LOAD,


STORE and ADD. The instructions are specific to the hardware being
programmed because different

4
CPUs use different programming languages.

And finally, every assembly language instruction is translated into a


single machine code instruction.

5
Difference between Compiler and Interpreter

Compiler Interpreter
Translates the whole program to Translates and executes one line at
produce the executable object code. a time.
Compiled programs execute faster as Interpreted programs take more
they are already in machine code. time to execute because each
instruction is translated before
being executed.
Users do not need to have the Users must have the interpreter
compiler installed on their installed on their computer and
computer to run the software. they can see the source code.
Users cannot see the actual source Users can see the source code and
code when you distribute the can copy it.
program.
Used for software that will run Used for program development and
frequently or copying software sold when the program must be able to
to a third party. run on multiple hardware
platforms.

Difference between low-level and high-level languages

Type of Example Description Example Instructions


Languag Language
e
High- Pascal, Cobol, Independent payRate = 10000
level Fortran, of hardware hours = 33.5
Languag Visual Basic, (portable). salary = payRate *
e C, C++, Translated hours
Python, Java using either
a compiler
or

6
interpreter.
One statement
translated into
many machine
code
instructions.
Low- Assembly Translated using LDA1
level language an assembler. One 81
Languag statement ADD
e translated into 93
machine code STO1
instruction. 85
Machine Code Executable binary 110100101010000011
code produced 101010
either by a 00101101
compiler,
interpreter or
assembler.

1.2.3 Advantages of high-level a nd low-level programming language

1.2.3.1 Advantages of high-level language

Most software are developed using high-level languages for the following
reasons:

● High-level languages are relatively easy to learn and much faster to

program in.

● Statements within these languages look like the natural English

language, including mathematical operators making it easier to read,


understand, debug and maintain.

● Complexed assignment statements such as x=(sqr(b^2-4*a*c))/(2*a)

7
● Allowing the programmer to show how the algorithm will solve a problem

in a clearer and more straightforward way.

8
● Specialized high-level languages have been developed to make the

programming as quick and easy as possible for particular applications


such as SQL, specially written to make it easy to search and maintain
databases. HTML, CSS and JavaScript were also developed to help
people create web pages and websites.

1.2.3.2 Advantages of low-level languages

● Assembly language is often used in embedded systems such as systems

that control a washing machine, traffic lights, robots, etc.

● It has features that make it suitable for the following types of applications:

o It gives complete control to the programmer over the system


components, so it can be used to control and manipulate specific
hardware components.
o It has very efficient code that can be written for a particular
processor architecture, so will occupy less memory and execute
(run) faster than a compiled/interpreted high-level language.

1.3 Integrated Development Environments (IDE)

Integrated Development Environment or IDE for short is an application or


software which programmers use for programming.

An IDE is a windows-based program that allows programmers to easily manage


large software programs. It often helps them in editing, compiling, linking,
running, and debugging programs.

On Mac OS X, CodeWarrior, Xcode and Eclipse are examples of IDEs that are
used by many programmers. Under Windows OS, Visual Studio Code, Eclipse,
NetBeans, CodeBlocks are good examples of popular IDEs. Kylix, Dev-C++,
Eclipse, NetBeans are popular IDEs for developing applications under Linux
OS.

Most IDEs also support program development in several different programming


languages in addition to C, such as C#, C++, Java, etc.
9
CHAP 2. ALGORITHM

An Algorithm specifies a series of steps that performs a particular


computation or task. It is a step by step procedure of solving a problem. It was
originally born as part of mathematics from the Arabic writer Mu ḥammad ibn
Mūsā al-Khwārizmī, and now strongly associated with computer science. A
good algorithm means an efficient solution to be developed.

Ways of representing an algorithm

There are two main ways that algorithms can be represented – pseudocode and
flowcharts.

Most programs are developed using programming languages. These languages


have specific syntax that must be used so that the program will run properly.
Pseudocode is not a programming language, it is a simple way of describing a
set of instructions that does not have to use specific syntax.

Writing in pseudocode is similar to writing in a programming language. Each step


of the algorithm is written on a line of its own in sequence. Usually, instructions
are written in uppercase, variables in lowercase and messages in sentence
case.

In pseudocode, INPUT asks a question. OUTPUT prints a message on screen.

A simple program could be created to ask someone their name and age, and to
make a comment based on these. This program represented in pseudocode would
look like the following two examples:

Example 1:

START

DECLARE name, age

OUTPUT 'What is your name?'

10
INPUT name

STORE the user's input in the name variable

OUTPUT 'Hello' + name

OUTPUT 'How old are you?'

INPUT age

STORE the user's input in the age variable

IF age >= 70 THEN

OUTPUT 'You are aged to perfection!'

ELSE

OUTPUT 'You are a spring chicken!'

END

Example 2:

START

END

Pseudocode Guide:
11
General Syntax

● IntExp, BoolExp, CharExp and StringExp means any expression which can
be evaluated to an integer, Boolean, character or string respectively.
● Exp means any expression
● Emboldened pseudocode is used to indicate the keywords/operators.
● In this material, indexing for arrays and strings starts at 0 unless
specifically stated otherwise.

Variables and Constants

1. a ← 3
Variable
Identifier ← Exp 2. a← a + 1
assignment
3. a← c – 2

constant PI ←3.141
constant constant
Constant
IDENTIFIER ← Exp
assignment CLASS_SIZE ← 23

Arithmetic Operations

+ Standard use using brackets to make


precedence obvious. The
Standard - / symbol is used instead of ÷ for division
arithmetic
(for integer division use DIV.)
operations *
/

9 DIV 5 evaluates to 1

Integer division IntExp DIV IntExp 5 DIV 2 evaluates to 2

8 DIV 4 evaluates to 2

12
9 MOD 5 evaluates to 4
5 MOD 2 evaluates to 1
Modulus IntExp MOD IntExp
8 MOD 4 evaluates to 0
operator

Relational Operators for types that can be clearly ordered

4<6
Less than Exp < Exp

4.1 > 4.0


Greater than Exp > Exp

Exp = Exp 3=3


Equal to

Exp ≠ Exp True ≠ False


Not equal to

3≤4
Less than
or equal Exp ≤ Exp 4≤4
to

4≥3
Greater than
4.5 ≥ 4.5
or equal to Exp ≥ Exp

Boolean Operations

BoolExp AND (3 = 3) AND (3 ≤ 4)


Logical AND
BoolExp

(x < 1) OR (x > 9)
Logical OR BoolExp OR
BoolExp

NOT (another_go =
Logical NOT NOT BoolExp
False)

13
Condition-controlled Iteration

a←1
Repeat-until (repeat the statements REPEAT
REPEAT
until the Boolean expression is # statements here
PRINT a
True) UNTIL BoolExp
a←a+1
UNTIL a = 4
# will output 1 2 3

a←1
While (while the Boolean WHILE BoolExp WHILE a < 4
expression is True, repeat the # statements here PRINT a
statements) a←a+1
ENDWHILE
ENDWHILE
# will output 1 2 3

Count-controlled Iteration OR loops

FOR a ← 1 TO 3
FOR Identifier ←IntExp TO IntExp
OUTPUT a
# statements here
ENDFOR

14
For ENDFOR
# will output 1 2 3

Selection

IF BoolExp THEN a←1

# statements here IF (a MOD 2) = 0 THEN

If ENDIF OUTPUT 'even'


ENDIF

a←1
IF BoolExp THEN
# statements here IF (a MOD 2) = 0 THEN
OUTPUT 'even'
ELSE
ELSE
# statements here
If-else OUTPUT 'odd'

ENDIF
ENDIF

a←1
IF BoolExp THEN
IF (a MOD 4) = 0 THEN
# statements here
OUTPUT 'multiple of 4'
ELSE IF BoolExpTHEN
ELSE IF (a MOD 4) = 1 THEN
# statements here
OUTPUT 'leaves a remainder of1'
# possibly more
ELSE IF (a MOD 4) = 2 THEN
ELSE IFs
OUTPUT 'leaves a remainder of2'
ELSE
ELSE
# statements here
OUTPUT ‘leaves a remainder of 3’
ENDIF
ENDIF
Else-if

15
Arrays:

Arrays are fundamental data structures in computer programming that allow you to
store multiple values of the same data type in contiguous memory locations. They
play a crucial role in algorithms and are used to solve various computational
problems efficiently.

Identifier ← [Exp, Exp,…, Exp] primes ← [2, 3, 5, 7, 11, 13]


Assignment

primes[0]
# evaluates to 2

# start indexing at

# 0 unless specifically stated

# otherwise
Accessing an Identifier[IntExp]
element

primes[5] ← 17
Updating an
# array is now [2,3,5,7,11,17]
element Identifier[IntExp] ← Exp

tables ← [ [1, 2, 3],


[2, 4, 6],
[3, 6, 9],
[4, 8, 12]
]

tables[3][1]

16
# evaluates to 8 as second element

Accessing an # (with index 1) of fourth array


element in a # (with index 3) in tables is 8
two-
dimensional Identifier[IntExp][IntExp]

array

tables[3][1] ← 16

tables is now
Updating an
element in a # [[1, 2, 3],
two- Identifier[IntExp][IntExp]←Exp

dimensional # [2, 4, 6],

array
# [3, 6, 9],
# [4, 16, 12]

LEN(primes)

# evaluates to 6 using example above

LEN(tables)
# evaluates to 4 using example above
LEN(tables[0])
# evaluates to 3 using example above

Array length LEN(Identifier)

17
Comments

Single line comments # comment

Multi-line comments # comment


# comment and so on

Flowchart

A flowchart is simply a graphical representation of steps within an Algorithm. It


shows steps in sequential order and is widely used in presenting the flow of
algorithms, workflow or processes. Typically, a flowchart shows the steps as
using desiccated flowchart symbols, and their order by connecting them by
arrows.

Flow chart symbols

18
19
Examples of flowcharts

1. Find the sum of 529 and 256

Sum =875

20
2.1. Qualities of a good algorithm
1. Input and output should be well defined with precision.
2. Each step in an algorithm should be clear and unambiguous.
3. An algorithm should be most effective among many different ways to solve
a problem.
4. An algorithm should be human understandable, it shouldn't have
computer code. Instead, the algorithm should be written in such a way
that it can be used in similar programming languages.
5. A good algorithm should be programming language independent, i.e can
be implemented by any software developer using any programming
language.

2.2. Real life Example


Producing a bread at the bakery
To bake a bread, we must have some followed steps:

0. Start
1. Preheat the oven;
2. Mix flour, sugar, and other ingredients;
3. Pour into a baking pan;
4. Heat for some
times 5. … …

n-1. Get the bread out of the baking pan

n. Stop

2.3. Programming Examples of Algorithm


I. Calculate the sum of any two numbers and print the sum
1. Start
2. Declare number type variables A, B and sum
3. Input A
4. Input B

21
5. Compute A+B into Sum
6. Output Sum
7. Stop

Pseudo code

START

VAR A,B,
Sum; GET A;
GET B;
Sum←A+B;
PRINT Sum;
STOP

Flow chart

II. Find the maximum number in a collection/list of numbers

22
List of steps

1. Start
2. Declare Variables
c[n] # array to hold n numbers
max # to hold the maximum number
3. Assign the first number in the list to max
4. Iterate through all numbers in the list comparing the value of max to
the next number in the list. If the number in the list is greater than
max, change the value of max by the next number in the list.
5. Return max/Print max
6. End

Pseudocode
START
DECLARE C, max, i
C←[val1,val2,.....valn]
max←C[0]
FOR i←1 TO n-1
IF C[i]>max THEN
max←C[i]
ENDIF
ENDFOR
PRINT max
STOP

III. Calculate the sum and average of all even numbers between 1 and n

Pseudocode
START
VAR sum←0, average, i

23
INPUT n
FOR i←1 TO n
IF i MOD 2=0 THEN
sum←sum+i
ENDIF
ENDFOR
average←sum/n
PRINT average
END

IV. Write an algorithm to find the largest among three different numbers

Pseudocode
START
DECLARE n1, n2, n3, largest
INPUT n1,n2,n3
IF n1>n2 THEN
IF n1>n3 THEN
n1←largest
ELSE IF n3>n1 THEN
n3←largest
ENDIF
ELSE IF n2>n1 THEN
n2←largest
END IF
PRINT largest
END

24
V. Write an algorithm to check whether a number entered by a user is
prime or not.
Algorithm:
START
DECLARE n, lv, flag←1
INPUT n
FOR lv←n-1 To 3
IF n%lv=0 THEN
flag←0
BREAK
END IF
END FOR
IF flag = 0 THEN
PRINT “n is not prime”
ELSE
PRINT “n is prime”
END IF
STOP
VI. Define an algorithm to find the number of digits in any given positive
integer number n.
For example, if n is 10, the number of digits is 2 (1 and 0), if n is 527, the
number of digits is 3 (5, 2 and 7)
1. START
2. VAR n, counter←0
3. INPUT n
4. REPEAT
5. n←n DIV 10 # integer division
6. counter←counter+1 # increment counter by one
7. UNTIL n=0
8. RETURN/OUTPUT counter #counter will store the number of digits
9. END

25
VII. Define an algorithm to find the greatest common divisor (GCD)
between to numbers

26
CHAP 3: C DATA TYPES
Prerequisite:
1. Number systems:
https://docs.google.com/document/d/1OtiVijwX7A96kC1ifrE3KHj1U-
UgpvhN/edit?
usp=sharing&ouid=111492439619719304666&rtpof=true&sd=true
2.

Broadly, there are 5 different categories of data types in the C language, they
are:

Category Example
Primary character, integer, floating-point,
double.
Derived Array, structure, union, pointer,
function.
Enumeration Enums
Bool type true or false
Void Empty value

3.1 Primary Data types in C

The C language has 5 basic (primary or primitive) data types, they are:

1. Character - American Standard Code for Information Interchange (ASCII)


character set or generally a single alphabet character like 'a', 'B', etc.
2. Integer - Used to store whole numbers like 1, 2, 100, 1000, etc.
3. Floating-point - Decimal point or real numbers values like 99.9, 10.5,
etc…, that have either a fractional form or an exponent form.
4. Double - Very large numeric values which are not allowed in Integer or
Floating point type.
5. Void - This means no value. This data type is mostly used when we define
functions.

27
There are different keywords to specify these data types, the keywords are:

Datatype Keyword
Character char
Integer int
Floating-point float
Double double
Void void

Each data type has a size defined in bytes (B(1B=8 bits(b))) and has a range for
the values that these data types can hold.

3.1.1. Size of different Data Types

The size for different data types depends on the compiler and processor types,
in short, it depends on the Computer on which you are running the C language
and the version of the C compiler that you have installed.

3.1.1.1. character

The char datatype is 1 byte in size or 8 bits. This is mostly the same and is not
affected by the processor or the compiler used.

3.1.1.2. integer

There is a very easy way to remember the size for integer data type. The size of
the integer data type is usually equal to the word length of the execution
environment of the program. In simpler words, for a 16- bit environment,
integer is 16 bits or 2 bytes, and for a 32-bit environment, int is 32 bits or 4
bytes. Unfortunately, this rule is not applicable in a 64-bit environment
where the size remains the same as in a 32-bit environment.

28
3.1.1.3. float

The float data type is 4 bytes or 32 bits in size. It is a single-precision data


type that is used to hold decimal values. It is used for storing large values.

float is a faster data type as compared to double, because double data type
works with very large values, hence it is slow.

3.1.1.4. double

The double datatype is 8 bytes or 64 bits in size. It can store values that are
double the size of what a float data type can store, hence it is called double.

In the 64 bits, 1 bit is for sign representation, 11 bits for the exponent, and
the rest 52 bits are used for the mantissa.

The double data type can hold approximately 15 to 17 digits, before the
decimal and after the decimal.

3.1.1.5. void

The void data type is 0 bytes means nothing, hence it doesn't have a size.

Before moving on to the range of values for these data types, there is one more
important concept to learn, which is Data Type modifiers.

3.1.2. Data Type Modifiers

In the C language, there are 4 data type modifiers that are used along with
the basic data types to categorize them further.
For example, if you say, there is a playground, the other person will know that
there is a playground, but you can be more specific and say, there is a Cricket

29
playground or a Football playground, which makes it even more clear for the
other person.

Similarly, there are modifiers in the C language, to make the primary data
types more specific. Following are the modifiers:
6. signed
7. unsigned
8. long
9. short

As the name suggests, signed and unsigned are used to represent the signed (+
and -) and unsigned (only +) values for any data type. And long and short
affects the range of the values for any datatype.

For example, signed int, unsigned int, short int, long int, etc. are all valid
data types in the C language.

Now let's see the range for different data types formed as a result of the 5
primary data types along with the modifiers specified above.

3.1.3 Data Type Value Ranges in C

In the table below we have the range for different data types in the C language.

Format
Typ Typical Size in Minimal Range
Specifier
e Bits
Char 8 -128 to 127 %c
unsigned char 8 0 to 255 %c
signed char 8 -128 to 127 %c
Int 16 or 32 -32,768 to 32,767 %d, %i
unsigned int 16 or 32 0 to 65,535 %u
signed int 16 or 32 Same as int %d, %i
30
short int 16 -32,767 to 32,767 %hd
unsigned short 16 0 to 65,535 %hu
int
signed short int 16 Same as short int %hd
long int 32 -2,147,483,648 to %ld, %li
2,147,483,647
-(263 - 1) to 263 - 1
long long int 64 %lld, %lli
(Added by C99
standard)
signed long int 32 Same as long int %ld, %li
unsigned long int 32 0 to 4,294,967,295 %lu

Modified data types


Format
Typ Typical Size Minimal Range
Specifie
e in Bits
r
unsigned long 64 264 - 1 (Added by C99 %llu
long int standard)
1E-37 to 1E+37 with
Float 32 %f
six digits of
precision
1E-37 to 1E+37 with
Double 64 %lf
ten digits of
precision
1E-37 to 1E+37 with
long double 80 %Lf
ten digits of
precision

As you can see in the table above, with different combinations of the datatype
and modifiers the range of value changes.

31
When we want to print the value for any variable with any data type, we have
to use a format specifier in the printf() statement.

What happens if the value is out of Range?

Well, if you try to assign a value to any datatype which is more than the allowed
range of value, then some C language compiler will give an error and others will
give a warning. Here is a simple code example to show this,

Which results the following output:

When a type modifier is used without any data type, then the int data type
is set as the default data type. So, unsigned means unsigned int, signed
means signed int, long means long int, and short means short int.

What do signed and unsigned mean?

32
This is a little tricky to explain, but let's try.

In simple words, the unsigned modifier means all positive values, while the
signed modifier means both positive and negative values.

When the compiler gets a numeric value, it converts that value into a binary
number, which means a combination of 0 and 1. For example, 32767 in binary
is 01111111 11111111, and 1 in binary
is 01 (or 0001), 2 is 0010, and so on.

In the case of a signed integer, the Most Significant Bit(MSB) which is the
highest order bit or the first digit from left (in binary) is used as the sign flag. If
the sign flag is 0, the number is positive, and if it is 1, the number is
negative.

And because one bit is used for showing if the number is positive or negative,
hence there is one less bit to represent the number itself, hence the range is
less.

For signed int, 11111111 11111111 means -32,767 and because the first bit
is a sign flag to mark it as a negative number, and rest represent the number.
Whereas in the case of unsigned int, 11111111 11111111 means 65,535.

A simple program to display the size of different data types:

//Size of primary data types in bytes


#include<stdio.h>
int main(){
printf("Size of Integer: %ld \n", sizeof(int));
printf("Size of Character: %ld \n", sizeof(char));
printf("Size of Float: %ld \n", sizeof(float));
printf("Size of Double: %ld \n", sizeof(double));
printf("Size of Signed Integer: %ld \n", sizeof(signed int));
33
printf("Size of Signed Character: %ld \n", sizeof(signed char));
printf("Size of unsigned Integer: %ld \n", sizeof(unsigned int));
printf("Size of Unsigned Character: %ld \n", sizeof(unsigned char));
printf("Size of Long Integer: %ld \n", sizeof(long int));
printf("Size of Long Double: %ld \n", sizeof(long double));
return 0;
}

The following is the output:

3.1.4 Primary data types declaration and initialization

Some c Compiler obliged the variable initialization after during the declaration.

34
The following are the initial values to be given for best practices, even if they can
be changed depending on the problem to be solved.

Data type Initial value

int 0

char '\0'

float 0

double 0

void nothing

3.2 Operators in C language


https://docs.google.com/document/d/1c82fdn4bRVVtE0wZCnv-
Ow6sTztOQFAdNXpWEsWuJyw/edit

3.3. Derived Data Types

Derived data types are nothing but primary data types a little twisted or grouped
together like array, function types, structure, union, pointer etc.
As data type determines the type of data a variable can hold; Then I can confirm
that : “ If a variable x is declared as type int, then it means that x will only hold
integer values for its whole life !”. Every variable which is used in the program
must be declared as what data-type it is.

3.3.1. Arrays

An array is a collection of a fixed number of values of a single type. For example:


if you want to store 100 integers in a sequence, you can create an array for it.

For example,

35
int data[100];

states that ”data” is a variable capable of storing one hundred integer numbers.
So, it behaves like a collection of a hundred variables of the same type, int.
The size and type of arrays cannot be changed after its declaration.

One-dimensional arrays Declaration, Initialization and Access

type name[number of elements];

For example, if we want an array of six integers (or whole numbers), we write:

int numbers[6]; and for a six character array called


letters:, char letters[6];
and so on.

You can also initialize as you declare. Just put the initial elements in
curly brackets separated by commas as the initial values:

36
type name[number of elements]={my comma-separated values}, please note that
values in an array are comma separated.
For example, if we want to initialize an array with six integers, with 0, 0, 1, 0, 0, 0
as the initial values then we will easily do it as bellow:
int point[6]={0,0,1,0,0,0};

Though when the array is initialized as in this case, the array dimension may be
omitted, and the array will be automatically sized to hold the initial data,interesting
that the size of an array can dynamically be determined at run time:
int point[]={0,0,1,0,0,0};

This is very useful in that the size of the array can be controlled by simply adding
or removing initialized elements from the definition without the need to adjust the
size.
If the size is specified, but not all elements in the array are initialized, the
remaining places will contain a default value of that data type like 0 in the above
case of integers. This is very useful, especially when we have very large arrays.
int numbers[2000]={25};

The above example sets the first value of the array of numbers to 25, and the rest
to 0 s.
How to initialize an array?

It's possible to initialize an array during declaration. For example,

float marks[5] = {19, 10, 8, 17, 9};

One dimensional arrays in C are indexed starting at 0, as opposed to starting at 1


in real life counting. The first element of the array above is marks[0]. The index to
the last value in the array is the array size minus one. In the example above the
subscripts run from 0 through 4. C does not guarantee bounds checking on array
accesses.
Array’s Elements access

You can access elements of an array by indices( indexes).

Suppose you declare an array called point as indicated below. The first element is
point[0], second element is point[1] and so on until when you reach the 6 th

37
element.
The compiler may not complain about the following (though the best compilers
do):
char point[6] = { 1, 2, 3, 4, 5, 6 };

38
//examples of accessing outside the array. A compile error is not always raised

y = point[15];//the array index out of bound is not thrown but really the error has
occurred
y = point[-4];//the array index out of bound is not thrown but really the error has
occurred
y = point[z];//the array index out of bound is not thrown but really the error has
occurred

Note: Your program will run but actually it is erroneous, so unexpected results.

If we want to access a variable stored in an array, for example with the above
declaration, the following code will store 3 in the variable x
int x;

x = point[2];//because the item with index 2 is 3

During program execution, an out of bounds array access does not always cause a
runtime error. Your program may happily continue after retrieving a value from
point[-1]. To alleviate indexing problems, the sizeof() expression is commonly used
when coding loops that process arrays.
Many people use a macro that in turn uses sizeof() to find the number of elements
in an array, a macro variously named "lengthof()","MY_ARRAY_SIZE()" or
"NUM_ELEM()","SIZEOF_STATIC_ARRAY()",etc.
int ix;

short anArray[]= { 3, 567, 9, 12, 15 };

for (ix=0; ix< (sizeof(anArray)/sizeof(short)); ++ix) {

//Do Some thing With anArray[ix] element;

Notice in the above example, the size of the array was not explicitly specified but
the compiler will know how to size it at 5 because of the five values in the
initialization.
39
Adding an additional value to the list will cause it to be sized to six, and because
of the sizeof expression in the for loop, the code automatically adjusts to this
change. Good programming practice is to declare a variable size , and let it store
the number of elements in the array.

40
Int size = sizeof(anArray)/sizeof(short) Few
key notes:
• Arrays have 0 as the first index not 1. In this example, marks[0]
• If the size of an array is n, to access the last element, n-1 index is used. In
this example, marks[1999] , ok n-1 is equal to 1999 as n was

2000; I get it right!


• Suppose the starting address of marks[0] is 2120d. Then, the next address,
marks[1], will be 2124d, address of marks[2] will be 2128d and so on. It's
because the size of a float is 4 bytes.

C also supports multidimensional arrays (or, rather, arrays of arrays). The simplest
type is a two dimensional array.

Two-dimensional arrays Declaration Initialization and Access

This creates a rectangular array made of rows and columns.

Each row has the same number of columns and each column has the same
number of rows. For example to declare a char array with 3 rows and 5 columns
we write in C

char two_d[3][5];

To access/modify a value in this array we need two subscripts: char


ch;
ch = two_d[2][4];// Array access ie. getting the element at rows index 2 and at
column index 4.
or

two_d[0][0] = 'x'; // Array initialization ie. putting an element x at the row 0 and
column 0 indexes.
Similarly, a two-dimensional array can be initialized like this:

41
int two_d[2][3] = {

{ 5, 2, 1 }, // row one has three columns

{ 6, 7, 8 } // row two has three columns

};

42
The amount of columns must be explicitly stated; however, the compiler will find
the appropriate amount of rows based on the initialized list.
Example 2:

float x[3][4];

Here, x is a two-dimensional (2d) array. The array can hold 12 elements. You can
think of the array as a table with 3 rows and each row has 4 columns as illustrated
below:

Similarly, you can declare a three-dimensional (3d) array. For example,

float y[2][4][3];

Here, the array y can hold 24 elements(2*4*3).

Initialization of two dimensional array

// Different ways to initialize two-dimensional array

int c[2][3] = {

{1, 3, 0},

{-1, 5, 9}

};

43
int c[][3] = {

{1, 3, 0},

{-1, 5, 9}

};

int c[2][3] = {1, 3, 0, -1, 5, 9};

Initialization of a three-dimentional array

int test[2][3][4] = {

{{3, 4, 2, 3}, {0, -3, 9, 11}, {23, 12, 23, 2}},

{{13, 4, 56, 3}, {5, 9, 3, 5}, {3, 1, 4, 9}}};

3.3.1.1. STRINGS

How to declare a string?

Before you can work with strings, you need to declare them first. Since string is an
array of characters. You declare strings in a similar way like you do with character
arrays.
Here's how you declare a string s:
char s[5];

5 memory address locations are allocated from the size 5 of the array.

3.3.1.1.1 How to initialize strings?

44
You can initialize strings in a number of ways.

1. char c[] = "abcd";

2. char c[50] = "abcd";

3. char c[] = {'a', 'b', 'c', 'd', '\0'};

4. char c[5] = {'a', 'b', 'c', 'd', '\0'};

All of the above four initialization statements will create a string c (character array )
to just hold 5 characters.

3.3.1.1.2. Read String from the user

You can use the scanf() function from the stdio library to read a string.

The scanf() function reads the sequence of characters until it encounters a


whitespace (space, newline, tab etc.) and stops there.

Example : scanf() to read a string

#include <stdio.h>

int main()
{

45
char name[20];
printf("Enter name: ");
scanf("%s", name);
printf("Your name is %s.", name);
return 0;
}

Output:

This output is questionable, right?

Even though Dennis Ritchie was entered in the above program, only "Dennis"

was stored in the name string. It's because there was a space after Dennis.

3.3.1.1.3. Then How to read a line of text as it contains some white spaces?

You can use gets() function to read a line of string.

And, you can use puts() or printf () functions to display the string on the console.

Use of gets() and puts()

#include <stdio.h>

int main()

char name[30];

printf("Enter name: ");

gets(name); // read string


printf("Your Name is: ");

puts(name); // display string

printf("\n");
46
return 0;

When you run the program, the output will be:

C has no string handling facilities built in; consequently, strings are defined as
arrays of characters; I repeat as arrays of characters OK. C allows a character
array to be represented as a character string rather than a list of characters, good!
With the null terminating character automatically added to the end. For example, to
store the string "MUKAJISTOS", we would write

char string[10] = "ABCDXYZMNO";


or
char string[10] = {'A', 'B', 'C', 'D', 'X', 'I', 'Y', 'Z', 'M', 'N', '\0'};

In the first example, the string will have a null character ('\0') automatically
appended to the end by the compiler; by convention, library functions expect strings
to be terminated by a null character ('\0'). The latter declaration indicates individual
elements, and as such the null terminator ('\0') needs to be added manually.
Strings do not always have to be linked to an explicit variable. As you have
seen already, a string of characters can be created directly as an unnamed
string that is used directly (as with the printf functions.)

To create an extra long string, you will have to split the string into multiple sections,
by closing the first section with a quote, and recommencing the string on the next
line (also starting and ending in a quote):
char string[58] = "This is a very, very long " "string that requires two lines.";
While strings may also span multiple lines by putting the backslash character at
the end of the line, this method is deprecated.
There is a useful library of string handling routines which you can use by including
another header file.

47
#include <string.h> //new header file

This standard string library will allow various tasks to be performed on strings.

3.3.1.1.4. String manipulation functions

You need to often manipulate strings according to the need of a problem. Most, if not
all, of the time string manipulation can be done manually but, this makes
programming complex and large. To solve this, C supports a large number of string
handling functions in the standard library "string.h".

Commonly used string handling functions are discussed below:

Function Work of Function

strlen() computes string's length

strcpy() copies a string to another

strcat() concatenates(joins) two strings

strcmp() compares two strings

strlwr() converts string to lowercase

strupr() converts string to uppercase

Classwork: Every student is requested to find a real word case each of those functions
is required and use them in a C program.

48
3.3.1.1.5. Passing Strings to Function
Strings can be passed to a function in a similar way as arrays.
Example
#include <stdio.h>
#include<string.h>
void displayString(char str[]);
int main(){
char str[50];
printf("Enter string: ");
fgets(str, sizeof str, stdin);
displayString(str);// Passing string to function return 0;
}
void displayString(char str[])
{
printf("The passed String was: ");
puts(str);
}

Sample output:

C has no string handling facilities built in; consequently, strings are defined
as arrays of characters; I repeat as arrays of characters OK. C allows a
character array to be represented as a character string rather than a list of
characters, good! With the null terminating character automatically added to
the end. For example, to store the string "MUKAJISTOS", we would write
char string[10] =
"MUKAJISTOS"; or
char string[10] = {'M', 'U', 'K', 'A', 'J', 'I', 'S', 'T', 'O', 'S', '\0'};
In the first example, the string will have a null character ('\0') automatically
appended to the end by the compiler; by convention, library functions expect
strings to be terminated by a null character ('\0'). The latter declaration
indicates individual elements, and as such the null terminator ('\0') needs to
be added manually.
49
Strings do not always have to be linked to an explicit variable. As you have
seen already, a string of characters can be created directly as an unnamed
string that is used directly (as with the printf functions.)

To create an extra long string, you will have to split the string into multiple
sections, by closing the first section with a quote, and recommencing the string
on the next line (also starting and ending in a quote):
char string[58] = "This is a very, very long " "string that requires two
lines.";
While strings may also span multiple lines by putting the backslash
character at the end of the line, this method is deprecated.
There is a useful library of string handling routines which you can use by
including another header file.

#include <string.h> //new header file

This standard string library will allow various tasks to be performed on strings.

50
3.3.1.2. Sorting an array

Computers are designed to quickly and merrily accomplish boring tasks, such as
sorting an array. In fact, they love doing it so much that “the sort” is a basic
computer concept upon which many theories and algorithms have been written.

The simplest sort is the bubble sort, which not only is easy to explain and
understand but also has a fun name(Bubble Sort). It also best shows the basic
array-sorting philosophy, which is to swap values between two elements. Goog now
we all know what sorting is really about!! It is about swapping elements: SIMPLE

3.3.1.2.1. Bubble sort

Bubble Sort is a simple algorithm which is used to sort a given set of n elements
provided in the form of an array with n number of elements. Bubble Sort compares
all the elements one by one and sorts them based on their values.
If the given array has to be sorted in ascending order, then bubble sort will start by
comparing the first element of the array with the second element, if the first element
is greater than the second element, it will swap both the elements, and then move
on to compare the second and the third element, and so on.

51
If we have total of n elements, then we need to repeat this process for n-1

times.

It is known as bubble sort, because with every complete iteration the largest
element in the given array, bubbles up towards the last place or the highest index,
just like a water bubble rises up to the water surface.

Sorting takes place by stepping through all the elements one-by-one and comparing
it with the adjacent element and swapping them if required.
Implementing Bubble Sort Algorithm

Following are the steps involved in bubble sort(for sorting a given array in ascending
order):

1. Starting with the first element(index = 0), compare the current element with
the next element of the array.
2. If the current element is greater than the next element of the array, swap
them.
3. If the current element is less than the next element, move to the next
element. Repeat Step 1.
Let's consider an array with values {5, 1, 6, 2, 4, 3}

Below, we have a pictorial representation of how bubble sort will sort the given
array.

52
So as we can see in the representation above, after the first iteration, 6 is placed at
the last index, which is the correct position for it.
Similarly after the second iteration, 5 will be at the second last index, and so on.

53
3.3.1.2.2. Selection sort

Selection sort is conceptually the most simplest sorting algorithm. This algorithm
will first find the smallest element in the array and swap it with the element in the
first position, then it will find the second smallest element and swap it with the
element in the second position, and it will keep on doing this until the entire array
is sorted. Not that now we are doing ascending order sorting; so, for
descending you will just change the direction of the comparison operator
It is called selection sort because it repeatedly selects the next-smallest /greatest
element and swaps it into the right place.

How Selection Sort Works?

Following are the steps involved in selection sort(for sorting a given array in
ascending order):
1. Starting from the first element, we search the smallest element in the array,
and replace it with the element in the first position.
2. We then move on to the second position, and look for the smallest element
present in the sub array, starting from index 1, till the last index.
3. We replace the element at the second position in the original array, or
we can say at the first position in the sub array, with the second smallest
element.
4. This is repeated, until the array is completely sorted.

Let's consider an array with values {3, 6, 1, 8, 4, 5}


Below, we have a pictorial representation of how selection sort will sort the
given array.

In the first pass, the smallest element will be 1, so it will be placed at the first
position.
Then leaving the first element, the next smallest element will be searched,
from the remaining elements. We will get 3 as the smallest, so it will be then
placed at the second position.

54
Then leaving 1 and 3(because they are at the correct position), we will search
for the next smallest element from the rest of the elements and put it at third
position and keep doing this until the array is sorted.

Finding Smallest Element in a sub array


In the selection sort, in the first step, we look for the smallest element in the
array and replace it with the element at the first position. This seems doable,
isn't it? Consider that you have an array with the following values {3, 6, 1, 8, 4,
5}. Now as per selection sort, we will start from the first element and look for the
smallest number in the array, which is 1 and we will find it at the index 2.
Once the smallest number is found, it is swapped with the element at the first
position.
Well, in the next iteration, we will have to look for the second smallest number
in the array. How can we find the second smallest number? This one is tricky?
If you look closely, we already have the smallest number/element at the first
position, which is the right position for it and we do not have to move it
anywhere now. So we can say that the first element is sorted, but the elements
to the right, starting from index 1 are not.
So, we will now look for the smallest element in the subarray, starting from
index 1, to the last index.
Confused? Give it time to sink in.
After we have found the second smallest element and replaced it with an
element on index 1(which is the second position in the array), we will have the
first two positions of the array sorted.
Then we will work on the sub array, starting from index 2 now, and
again looking for the smallest element in this sub array.

Implementing Selection Sort Algorithm

In the C program below, we have tried to divide the program into small
functions, so that it's easier for you to understand which part is doing

55
what.There are many different ways to implement selection sort algorithm, here
is the one that we like:

// C program implementing Selection sort

/* function to swap elements at the


given index values*/
void swap(int array[], int firstIndex, int
secondIndex)
{
int temp;
temp = array[firstIndex];
array[firstIndex] = array[secondIndex];
array[secondIndex] = temp;
}

/* function to look for smallest element


in the given subarray*/
int indexOfMinimum(int array[], int
startIndex, int n)
{
int minValue = array[startIndex];
int minIndex = startIndex;

for(int i = minIndex + 1; i < n; i++) {


if(array[i] < minValue)
{
minIndex = i;
minValue = array[i];
}
}
return minIndex;
56
}

void selectionSort(int array[], int n)


{
for(int i = 0; i < n; i++)
{

int index = indexOfMinimum(array, i, n);


swap(array, i, index);
}

}
/* the function that prints the content of
any size array*/
void printArray(int array[], int size)
{
int i;
for(i = 0; i < size; i++)
{
printf("%d ", array[i]);
}
printf("\n");
}

int main()
{
int array[] = {46, 52, 21, 22, 11};
int n = sizeof(array)/sizeof(array[0]);
selectionSort(array, n);

57
printf("Sorted array: \n");
printArray(array, n);
return 0;
}

And this is the output:

I advise each leaner to rewrite down the above program

Note: Selection sort is an unstable sort i.e it might change the occurrence of
two similar elements in the list while sorting. But it can also work as a stable
sort when it is implemented using a linked list. Oohh my God yoyoooo !! What
are those Linked lists? I wish you would wait until when you do the course of
data structures and algorithms, I like C programming almost everything was
thought of..

58
3.3.1.2.3. Insertion sort

Consider you have 10 cards out of a deck of cards in your hand. And they are
sorted, or arranged in the ascending order of their numbers.
If I give you another card, and ask you to insert the card in just the right position, so
that the cards in your hand are still sorted. What will you do?
Well, let me guess : “ you will have to go through each card from the starting or the
back and find the right position for the new card, comparing its value with each
card” Right ? . Ok, Once you find the right position, you will insert the card
there,Right ! You have done insertion, but is it an insertion sort ?

Similarly, if more new cards are provided to you, you can easily repeat the same
process and insert the new cards and keep the cards sorted too.

This is exactly how insertion sort works. It starts from index 1(not 0), and each
index starting from index 1 is like a new card that you have to take from the right
sub array(unsorted) to the sorted sub array on the left.

Following are some of the important characteristics of Insertion Sort:

1. It is efficient for smaller data sets, but very inefficient for large lists.

2. Insertion Sort is adaptive, that means it reduces its total number of steps if a
partially sorted array is provided as input, making it efficient.
3. It is better than Selection Sort and Bubble Sort algorithms.

4. Its space complexity is less. Like bubble Sort, insertion sort also requires a
single additional memory space.
5. It is a stable sorting technique, as it does not change the relative order of
elements which are equal

59
How Insertion Sort Works?

Following are the steps involved in insertion sort:

1. We start by making the second element of the given array, i.e. element at
index 1, the key. The key element here is the new card that we need to add to
our existing sorted set of cards(remember the example with cards above).
2. We compare the key element with the element(s) before it, in this case,
element at index 0:
• If the key element is less than the first element, we insert the key

element before the first element.

• If the key element is greater than the first element, then we insert it
after the first element.

3. Then, we make the third element of the array as key and will compare it
with elements to its left and insert it at the right position.
4. And we go on repeating this, until the array is sorted.

Let's consider an array with values {4,3,2,10,12,1,5,6}

Below, we have a pictorial representation of how bubble sort will sort the given
array.

60
As you can see in the diagram above, after picking a key, we start iterating over
the elements to the left of the key.

Implementing Insertion Sort Algorithm:


Below we have a simple implementation of Insertion sort in C language.

61
#include <stdio.h>

//member functions declaration

void insertionSort(int array[], int length);

void printArray(int array[], int size);

// main function

int main()

int array[8] = {4,3,2,10,12,1,5,6};

// calling insertion sort function to sort the array

insertionSort(array, 8);

return 0;

void insertionSort(int array[], int length)

int i, j, key;

for (i = 1; i < length; i++)

j = i;

while (j > 0 && array[j - 1] > array[j])

62
key = array[j];

array[j] = array[j - 1];

array[j - 1] = key;

j--;

printf("Sorted Array: ");

// print the sorted array

printArray(array, length);

// function to print the given array

void printArray(int array[], int size)

int j;

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

printf(" %d ",array[j]);

printf("\n");

Now let's try to understand the above simple insertion sort algorithm.
We took an array with 8 integers. We took a variable key, in which we put each
element of the array, during each pass, starting from the second element, that is

63
a[1].
Then using the while loop, we iterate, until j becomes equal to zero or we find an
element which is greater than key, and then we insert the key at that position.
We keep on doing this, until j becomes equal to zero, or we encounter an element
which is smaller than the key, and then we stop. The current key is now at the
right position.
We then make the next element as key and then repeat the same process.
In the above array, first we pick 1 as key, we compare it with 5(element before 1), 1
is smaller than 5, we insert 1 before 5. Then we pick 6 as key, and compare it with
5 and 1, no shifting in position this time. Then 2 becomes the key and is compared
with 6 and 5, and then 2 is inserted after 1. And this goes on until the complete
array gets sorted.

64
We continue to move towards the left if the elements are greater than the key
element and stop when we find the element which is less than the key element.
And, insert the key element after the element which is less than the key element.
Implementing Insertion Sort Algorithm:

Below we have a simple implementation of Insertion sort in C language.

3.3.2. Functions in C language

In c, we can divide a large program into the basic building blocks known as
function. The function contains the set of programming statements enclosed by { }.
A function can be called multiple times to provide reusability and modularity to
the C program. In other words, we can say that the collection of functions creates
a program. The function is also known as procedure or subroutine in other
programming languages.

Advantage of functions in C

There are the following advantages of C functions.

- By using functions, we can avoid rewriting the same logic/code again and
again in a program.
- We can call C functions any number of times in a program and from any place
in a program.
- We can track a large C program easily when it is divided into multiple
functions.
- Reusability is the main achievement of C functions.

Function Aspects

There are three aspects of a C function.

Function declaration A function must be declared globally in a c program to tell


65
the compiler about the function name, function parameters, and return type.
N.B: This depends on the C compiler!

Function call Function can be called from anywhere in the program. The
parameter list must not differ in function calling and function declaration. We
must pass the same number of functions as it is declared in the function
declaration.

Function definition It contains the actual statements which are to be executed.


It is the most important aspect to which the control comes when the function is
called. Here, we must notice that only one value can be returned from the
function.

# Function Syntax
aspect

1 Function declaration return_type function_name (parameters’ list);

2 Function call function_name (argument_list)

3 Function definition return_type function_name (parameters’ list)


{function body;}

NB:
- In function declaration, parameters’ list can be replaced by the list of their
types only. For example the function declaration void myFunction(int i,
char c, float f); can be replaced by void myFunction(int, char, float);
- The function declaration is not mandatory for some c compilers

Types of Functions in C language

There are two types of functions in C programming:

66
1. Library Functions: are the functions which are declared in the C header files such as
scanf(), printf(), gets(), puts(), ceil(), floor(), sin(), cos() etc. To use a function among these,
you must use the preprocessor directive having the header file in which that function is
defined.

2. User-defined functions: are the functions which are created by the C programmer, so that
he/she can use it many times. It reduces the complexity of a big program and optimizes the
code.

Different aspects of function calling

A function may or may not accept any argument. It may or may not return any
value. Based on these facts, There are four different aspects of function calls.

● function without arguments and without return value

● function without arguments and with return value

● function with arguments and without return value

● function with arguments and with return value

Example of Function without argument and return value

#include<stdio.h>
//Defining the function display()
void display(){
char names[50];
printf("Enter your names: \n");
fgets(names, sizeof (names), stdin);
printf("You said your names are: \n");
puts(names);
}
int main(){
display();//calling the function display()
return 0;
}

When you compile and run the above code, the result should look like this:

67
Example of a function without arguments and with return value

#include<stdio.h>
//Defining the function add()
void add(int a, int b){
printf("The sum of %d and %d is %d \n", a,b,a+b);
}
int main(){
int n1,n2;
printf("\n Enter two integers \n");
scanf("%d%d",&n1,&n2);
add(n1,n2);//calling the function add()
return 0;
}
And this is the sample execution of this program:

Example of a function with arguments and with return value


#include<stdio.h>
//Defining the function sum
int sum(int a, int b){
return a+b;
}
int main(){
int n1,n2,s;
printf("\n Enter two integers \n");
scanf("%d%d",&n1,&n2);

68
s=sum(n1,n2);//calling the function sum
printf("The calculated sum is %d ",s);
return 0;
}
with the following sample of output:

Example of a function with arguments but without return type


#include<stdio.h>
int main()
{
void square(float);//function declaration
float s;
printf("Give the side of Square\n");
scanf("%f",&s);
square(s); // function call
return 0;
}
void square(float side)
{
float area=side*side;
printf("The area of a square of side %f is %f ", side, area);

}
Which produce the following sample output:

Interested case of functions: Recursive functions in C

The C programming language allows any of its functions to call itself multiple times
in a program. Here, any function that happens to call itself again and again (directly
69
or indirectly), unless the program satisfies some specific condition/subtask is called
a recursive function.
In C language, recursion refers to the process in which a function repeatedly calls
its multiple copies when working on some very small problem. Here, the functions
that keep calling themselves repeatedly in a program are known as the recursive
functions, and such types of functions in which the recursive functions call
themselves are known as recursive calls.

The process of recursion in the C language consists of multiple recursive calls. And,
it is also a prerequisite that you choose a termination condition for the recursive
function- or else, the program will be stuck in a loop.

Pseudocode for Recursive Functions in C


Let us check the pseudocode used for writing the recursive function in any code:

if (base_test)

return given_value;

else if (another_base_test)

return other_given_value;

else

// Giving a Statement here;

recursive call;

Working of a Recursive Function in C

70
It is simple to understand how a recursive function works in the C language. It
involves certain tasks and divides them into various subtasks. Some of the subtasks
consist of termination conditions/conditions. These subtasks need to satisfy these
conditions to terminate the program. Else, as discussed above, a never-ending loop
will be created.

Next, the process of recursion finally stops, and we then get to derive the final result
from the recursive function. Here, we also have the concept of the base case. A base
case refers to the case where the function doesn’t recur, and thus, we have the base
case. There are various instances when the recursive function tries to perform a
subtask by repeatedly calling itself. It is known as the recursive case.

Let us take a look at the format used for writing the recursive function in C.

Examples
Here, we will write a C program that prints the 10th values of the Fibonacci series in
the form of output.

#include<stdio.h>

int numberfibonacci(int);

void main ()

int a,b,i;

printf("Please enter the value of the n number here (index on item in Fibonacci series) : ");

scanf("%d",&a);

b= numberfibonacci(a);

printf("\n The element at index %d in fibonaci series is %d \n",a, b);

int numberfibonacci(int a)

71
if (a==0)

return 0;

else if (a == 1)

return 1;

else

return numberfibonacci(a-1) + numberfibonacci(a-2);

The sample output generated here from the code mentioned above would be like this:

Let us take a look at another example. We will write a program in C that finds the factorial of
an available number using the recursive function and not loops.

#include<stdio.h>

long factorial(int n){

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

return 1;

72
else

return n*factorial(n-1);

int main(){

int number;

printf("\n Enter a Positive number:");

scanf("%d", &number);

printf("\nThe Factorial of %d is %ld \n",number, factorial(number));/* factorial function is


called here*/

return 0;

The sample output generated here from the code mentioned above would be:

N.B: Advantages and Disadvantages of Recursion

Recursion makes the program elegant and more readable. However, if performance
is vital then, use loops instead as recursion is usually much slower.
Note that every recursion can be modeled into a loop.

Need performance, use loops, however, code might look ugly and hard to read
sometimes. Need more elegant and readable code, use recursion, however, you are
sacrificing some performance. Now you know both, it's up to you to let us know how
good a programming analyst you are.

Exercises:

1. Define a function rectangleArea which receives two sides (side1 and side2) of

73
a rectangle as arguments. The function should then return the area of that
rectangle.
N.B: The values of arguments are assigned at run time, which means that the
function rectangleArea will calculate the area of any rectangle.
2. Write a program in C to find the sum of the series 1+½!+ ⅓!+¼!+ ⅕!+...+1/n!
using the user defined function(s).
N.B: n is given at run time and passed to the function as argument
3. Define a function in a c program which swaps two numbers

3.3.3. Pointer variables in C

3.3.3.1. Address in C language

Before you get into the concept of pointers, let's first get familiar with addresses
in C.
If you have a variable var in your program, &var will give you its address in the
memory, where & is commonly called the reference operator.

You must have seen this notation while using scanf() function. It was used in
the function to store the user inputted value in the address of var, I know you
have already seen the magic “&”.

scanf("%d", &var); // values are actually stored in memory locations of


variables
#include <stdio.h>
int main()
{
int var = 5;
printf("Value: %d\n", var);
printf("Address: %p\n", &var); //Notice, the ampersand(&) before var. return 0;
}

Output

74
Note: You may obtain different values of address while using this code.
In above source code, value 5 is stored in the memory location 0x7ffcac23e854. var
is just the name given to that location.

In C, you can create a special variable that stores the address (rather than the
value). This variable is called a : “pointer variable” or simply a: ”pointer”.

3.3.3.3. How to create a pointer variable?


Data_type *pointer_variable_name;
Example:
int *p;

Above statement defines p as a pointer variable.

Reference operator (&) and dereference operator (*)

As discussed, & is called a reference operator. It gives you the address of a


variable.
Likewise, there is another operator that gets you the value from the address, it is
called a dereference operator, which is *.
Below example clearly demonstrates the use of pointers, reference operator and
dereference operator.

Note: The * sign when declaring a pointer is not a dereference operator. It is just a
similar notation that creates a pointer.

Example: How Pointer Works?

#include <stdio.h>
int main()
{
int * pc, c;

c = 22;

75
printf("Address of c: %p\n", &c);
printf("Value of c: %d\n\n", c);

pc = &c;
printf("Address of c: %p\n", pc);
printf("Content pointed by pc: %d\n\n", *pc);

c = 11;
printf("Address of c: %p\n", pc);
printf("Content pointed by pc: %d\n\n", *pc);

// a pointer can change the value of a variable


*pc = 2;
printf("Address of c: %p\n", &c);
printf("Value of c: %d\n\n", c);
return 0;
}
Output

Explanation of the program

1. int* pc, c;
Here, a pointer pc and a normal variable c, both of type int, is created. Since
pc and c are not initialized at first, pointer pc points to either no address or a
random address. And, variable c has an address but contains a random

76
garbage value.
2. c = 22;

This assigns 22 to the variable c, i.e., 22 is stored in the memory location of


variable c.
Note that, when printing &c (address of c), we use %p since we are outputting
the address/pinter. (https://www.freecodecamp.org/news/format-specifiers-
in-c/)
N.B:
- The address is output in Hexadecimal format in this case.
- Some compilers use %u modifier and output the address in decimal format,
as a unsigned integer

3. pc = &c;

This assigns the address of variable c to the pointer pc.


You see the value of pc is same as the address of c and the value pointed by pc
is 22 as well.
4. c = 11;

This assigns 11 to variable c.


Since, pointer pc points to the same address, value pointed by pointer pc is
11 as well.

5. *pc = 2;

This changes the value at the memory location pointed by pointer pc to 2.


Since pc always points to c, the value of c is also changed to 2. This is now
more Interesting! How a pointer can easily modify the value of the variable it
points to.

Call a function by value and Call by reference in

There are two methods to pass the data into the function in C language, i.e.,
call by value and call by reference.

Call by value

77
- In the call by value method, the value of the actual parameters is copied
into the formal parameters. In other words, we can say that the value of the
variable is used in the function call in the call by value method.

- In the call by value method, we can not modify the value of the actual
parameter by the formal parameter.

- In call by value, different memory is allocated for actual and formal


parameters since the value of the actual parameter is copied into the formal
parameter.

- The actual parameter is the argument which is used in the function call
whereas the formal parameter is the argument which is used in the function
definition.

Call by reference

When we call a function by passing the addresses of actual parameters then


this way of calling the function is known as call by reference. In call by
reference, the operation performed on formal parameters affects the value of
actual parameters because all the operations performed on the value stored in
the address of actual parameters. It may sound confusing first but the following
example would clear your doubts.

Example 1:

#include <stdio.h>

void increment(int *var)

/* Although we are performing the increment on variable

* var, however the var is a pointer that holds the address

78
* of variable num, which means the increment is actually done

* on the address where value of num is stored.

*/

*var = *var+1;

int main()

int num=20;

/* This way of calling the function is known as call by

* reference. Instead of passing the variable num, we are

* passing the address of variable num

*/

increment(&num);

printf("Value of num is: %d", num);

return 0;

When the code above is compiled and executed, it produces the following result:

79
Example 2: Swapping Numbers

#include<stdio.h>

void swapnum ( int *var1, int *var2 )

int tempnum ;

tempnum = *var1 ;

*var1 = *var2 ;

*var2 = tempnum ;

int main( )

int num1 = 35, num2 = 45 ;

printf("Before swapping:");

printf("\nnum1 value is %d", num1);

printf("\nnum2 value is %d", num2);

/*calling swap function*/

80
swapnum( &num1, &num2 );

printf("\nAfter swapping:");

printf("\nnum1 value is %d", num1);

printf("\nnum2 value is %d", num2);

return 0;

The following is the output of the program:

3.3.3.3. Pointer access and errors

However, initializing pointers unnecessarily could hinder program analysis, thereby


hiding bugs.
In any case, once a pointer has been declared, the next logical step is for it to point
at something:

int a = 5;
int *ptr = NULL;

ptr = &a; // address to pointer assignment


This assigns the value of the address of a to ptr. For example, if a is stored at

81
memory location of 0x8130 then the value of ptr will be 0x8130 after the
assignment. To dereference the pointer, an asterisk is used again:
*ptr = 8;

82
This means take the contents of ptr (which is 0x8130), "locate" that address in
memory and set its value to 8. If a is later accessed again, its new value will be
8. Which means :”A pointer can change the value of a variable!”
This example may be clearer if memory is examined directly. Assume that a is
located at address 0x8130 in memory and ptr at 0x8134; also assume this is a 32-
bit machine such that an int is 32-bits wide. The following is what would be in
memory after the following code snippet is executed:
int a = 5;
int *ptr = NULL;

Address Contents
0x8130 0x00000005
0x8134 0x00000000

(The NULL pointer shown here is 0x00000000.) By assigning the address of a to ptr:
ptr = &a;
yields the following memory values:

Address Contents

0x8130 0x00000005
0x8134 0x00008130

Then by dereferencing ptr by coding:


*ptr = 8;
the computer will take the contents of ptr (which is 0x8130), 'locate' that address,
and assign 8 to that location yielding the following memory:
Address Contents
0x8130 0x00000008
0x8134 0x00008130

Clearly, accessing a will yield the value of 8 because the previous instruction
modified the contents of a by way of the pointer ptr.
Common mistakes when working with pointers
Suppose, you want a pointer pc to point to the address of c. Then,

83
int c, *pc;
// Wrong! pc is address whereas,
// c is not an address.
pc = c;
// Wrong! *pc is the value pointed by address whereas,
// &c is an address.
pc = &c;
// Correct! pc is an address and,
// &c is also an address.
ptr = &a;
// Correct! * ptr is the value pointed by address and,
// c is also a value (not address).
*pc = c;

3.3.3.4. Strings and pointer

Similarly like arrays, string names are "decayed" to pointers. Hence, you can use a
pointer with the same name as string to manipulate elements of the string.

Example : Strings and Pointers

#include <stdio.h>

int main(void) {
char name[] = "Harry Potter"; // A string initialization as a array of characters

printf("\n%c", *name);// Output: H


printf("\n%c", *(name+1));// Output: a
printf("\n%c", *(name+7));// Output: o

char *namePtr;

namePtr = name;

printf("\n%c", *namePtr);// Output: H


printf("\n%c", *(namePtr+1));// Output: a
printf("\n%c\n",*(namePtr+7));// Output: o

84
}
Output:

3.3.3.5 Dynamic memory allocation in C

In C, memory is allocated dynamically using standard library functions malloc(), calloc(), free()
and realloc() defined in the stdlib.h header file.

As you know, an array is a collection of a fixed number of values. Once the size of an array is
declared, you cannot change it.

Sometimes the size of the array you declared may be insufficient. To solve this issue, you can
allocate memory manually during run-time. This is known as dynamic memory allocation in C
programming.

C malloc()

The name "malloc" stands for memory allocation.

The malloc() function reserves a block of memory of the specified number of bytes. And, it returns
a pointer of void which can be casted into pointers of any form.

Syntax of malloc()

ptr = (castType*) malloc(size);

Example

ptr = (float*) malloc(100 * sizeof(float));

The above statement allocates 400 bytes of memory. It's because the size of the float is 4 bytes.
And, the pointer ptr holds the address of the first byte in the allocated memory.

The expression results in a NULL pointer if the memory cannot be allocated.

85
C calloc()

The name "calloc" stands for contiguous allocation.

The malloc() function allocates memory and leaves the memory uninitialized, whereas the calloc()
function allocates memory and initializes all bits to zero.

Syntax of calloc()

ptr = (castType*)calloc(n, size);

Example:

ptr = (float*) calloc(25, sizeof(float));

The above statement allocates contiguous space in memory for 25 elements of type float.

C free()

Dynamically allocated memory created with either calloc() or malloc() doesn't get freed on their
own. You must explicitly use free() to release the space.

Syntax of free()

free(ptr);

This statement frees the space allocated in the memory pointed by ptr.

Example 1: malloc() and free()

// Program to calculate the sum of n numbers entered by the user

#include <stdio.h>
#include <stdlib.h>

86
int main() {
int n, i, *ptr, sum = 0;

printf("Enter number of elements: ");


scanf("%d", &n);
ptr = (int*) malloc(n * sizeof(int));
// if memory cannot be allocated
if(ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
printf("Enter elements: ");
for(i = 0; i < n; ++i) {
scanf("%d", ptr + i);
sum += *(ptr + i);
}
printf("Sum = %d", sum);
// deallocating the memory
free(ptr);
return 0;
}
Sample Output

Here, we have dynamically allocated the memory for n number of int.

Example 2: calloc() and free()

// Program to calculate the sum of n numbers entered by the user

87
#include <stdio.h>
#include <stdlib.h>

int main() {
int n, i, *ptr, sum = 0;
printf("Enter number of elements: ");
scanf("%d", &n);

ptr = (int*) calloc(n, sizeof(int));


if(ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
printf("Enter elements: ");
for(i = 0; i < n; ++i) {
scanf("%d", ptr + i);
sum += *(ptr + i);
}

printf("Sum = %d", sum);


free(ptr);
return 0;
}
Sample Output

C realloc()

If the dynamically allocated memory is insufficient or more than required, you can change the size
of previously allocated memory using the realloc() function.

88
Syntax of realloc()

ptr = realloc(ptr, x);

Here, ptr is reallocated with a new size x.

Example 3: realloc()

#include <stdio.h>
#include <stdlib.h>

int main() {
int *ptr, i , n1, n2;
printf("Enter size: ");
scanf("%d", &n1);

ptr = (int*) malloc(n1 * sizeof(int));

printf("Addresses of previously allocated memory:\n");


for(i = 0; i < n1; ++i)
printf("%pc\n",ptr + i);

printf("\nEnter the new size: ");


scanf("%d", &n2);

// rellocating the memory


ptr = realloc(ptr, n2 * sizeof(int));

printf("Addresses of newly allocated memory:\n");


for(i = 0; i < n2; ++i)
printf("%pc\n", ptr + i);

free(ptr);

89
return 0;
}
Sample Output

The corresponding memory addresses in decimal are

1504083730344972

1504083730345036

(Previously allocated )

and

1504083730344972

1504083730345036

1504083730345100

(Newly allocated)

The presentation on this topic is here:


https://docs.google.com/presentation/d/1BamaqhnWuwhTwsuKhwEpDTAddLBuyuROBbe0jZRX
g_w/edit#slide=id.g230e362be33_0_199

90
3.3.3.6. Benefits of using pointers

Below we have listed a few benefits of using pointers:


1. Pointers are more efficient in handling Arrays and Structures.
2. Pointers allow references to function and thereby help in passing of
function as arguments to other functions.
3. They reduce the length of the program and its execution time as well.
4. They allow C language to support Dynamic Memory management.

91
3.3.4. STRUCTURES

A Structure is a collection of variables (can be of different types) under a single


name variable.
For example: You want to store information about a person: his/her name,
citizenship number and salary. You can create different variables name, citNo and
salary to store these information separately.
What if you need to store information of more than one person? Now, you need to
create different variables for each information per person: name1, citNo1, salary1,
name2, citNo2, salary2 oooh agree codes that will serve nothing in long run etc.
A better approach would be to have a collection of all related information
under a single name Person structure, and use it for every person.

3.3.4.1. How to define a structure?


Keyword struct is used for creating a structure with the following syntax:
struct [structure_name /tag]{ data_type member1; data_type member2;
...
data_type memebern;
}[variables]; //coma separated variables declaration

Here is an example:
struct Person{
char name[50];
int citNo;
float salary;
};
Here, a derived data type Person is defined.

3.3.4.2. Create structure variable

When a structure is defined, it creates a user-defined type. However, no storage or


memory is allocated. To allocate memory of a given structure type and work with it,
we need to create variables.

92
Here's how we create structure variables:

struct Person
{
char name[50];
int citNo;
float salary;
}person0, person2, Peter, Moses,Nina,Rwema;//one way

int main()
{
Person person1, person2, persons[20]; //variable declaration using Person
structure
return 0;
}

93
Another way of creating a structure variable is:
struct Person
{
char name[50]; int
citNo;
float salary;
} person1, person2, persons[20];

In both cases, two variables person1, person2, and an array variable


persons having 20 elements of type struct Person are created.

3.3.4.3. How to Access Members of a structure?

There are two types of operators used for accessing members of a structure.
1. Member operator(.)
2. Structure pointer operator(->) (this will be discussed in structure and
pointers)
Suppose, you want to access salary of person2. Here's how you can do it:
person2.salary // Very simple

Example:
// Program to add two distances which is in feet and inches
#include <stdio.h>

struct Distance

int feet;

float inch;

} dist1, dist2, sum;

int main()

94
{

printf("1st distance\n");

printf("Enter feet: ");

scanf("%d", &dist1.feet);

printf("Enter inch: ");

scanf("%f", &dist1.inch);

printf("2nd distance\n");

printf("Enter feet: ");

scanf("%d", &dist2.feet);

printf("Enter inch: ");

scanf("%f", &dist2.inch);

// adding feet

sum.feet = dist1.feet + dist2.feet;

// adding inches

sum.inch = dist1.inch + dist2.inch;

// changing feet if inch is greater than 12

while (sum.inch >= 12)

++sum.feet;

95
sum.inch = sum.inch - 12;

printf("Sum of distances = %d - %.1f\n", sum.feet, sum.inch);

return 0;

Sample Output

96
3.3.4.4. Keyword typedef In C

Keyword typedef can be used to simplify syntax of a structure.


This code
struct Distance{

int feet;
float inch;
};

int main() {
Distance d1, d2;
}
is equivalent to
typedef struct Distance{

int feet;
float inch;
} distances;

int main() {
distances d1, d2, sum; // declaring variable using typedof
}

The typedef is a keyword used in C programming to provide some meaningful names to the
already existing variable in the C program. It behaves similarly as we define the alias for the
commands. In short, we can say that this keyword is used to redefine the name of an already
existing variable.. Following is the general syntax for using typedef,
typedef <existing_name> <alias_name>
Let's take an example and see how typedef actually works.
typedef unsigned long ulong;
The above statement defines a term ulong for an unsigned long data type. Now
this ulong identifier can be used to define unsigned long type variables. ulong i, j;

Application of typedef
97
typedef can be used to give a name to user defined data type as well. Lets see its
use with structures.

typedef struct
{
type member1;
type member2;
type member3;
} type_name;
Here type_name represents the structure definition associated with it. Now this
type_name can be used to declare a variable of this structure type.

type_name t1, t2;

Example of Structure definition using typedef


#include<stdio.h>
#include<string.h>
typedef struct
{
char name[50];
int salary;
}emp;

void main( )
{
emp e1;
printf("\nEnter Employee record:\n");
printf("\nEmployee name:\t");
fgets(e1.name, sizeof(e1.name),stdin);
printf("\nEnter Employee salary: \t");
scanf("%d", &e1.salary);
printf("\nstudent name is %s", e1.name);
printf("\nSalary is %d \n", e1.salary);
}

98
Simple output:

99
Access structures members using pointers

To access members of a structure using pointers, we use the -> operator.

C program example:

#include <stdio.h>
struct person
{
int age;
float weight;
};

int main()
{
struct person *personPtr, person1;
personPtr = &person1;

printf("Enter age: ");


scanf("%d", &personPtr->age);

printf("Enter weight: ");


scanf("%f", &personPtr->weight);

printf("Displaying:\n");
printf("Age: %d\n", personPtr->age);
printf("weight: %f", personPtr->weight);

return 0;
}

Sample output

In this example, the address of person1 is stored in the personPtr pointer using personPtr
= &person1;

Now, you can access the members of person1 using the personPtr pointer.

Dynamic memory allocation of structs

100
Sometimes, the number of struct variables you declared may be insufficient. You may
need to allocate memory during run-time. Here's how you can achieve this in C
programming.

Example: Dynamic memory allocation of structs

#include <stdio.h>
#include <stdlib.h>
struct person {
int age;
float weight;
char name[30];
};

int main()
{
struct person *ptr;
int i, n;

printf("Enter the number of persons: ");


scanf("%d", &n);

// allocating memory for n numbers of struct person


ptr = (struct person*) malloc(n * sizeof(struct person));

for(i = 0; i < n; ++i)


{
printf("Enter first name and age respectively: ");

// To access members of 1st struct person,


// ptr->name and ptr->age is used

// To access members of 2nd struct person,


// (ptr+1)->name and (ptr+1)->age is used
scanf("%s %d", (ptr+i)->name, &(ptr+i)->age);
}

printf("Displaying Information:\n");
for(i = 0; i < n; ++i)
printf("Name: %s\tAge: %d\n", (ptr+i)->name, (ptr+i)->age);

return 0;
}

Sample output

101
3.3.4.5. Nested Structures

You can create structures within a structure in C programming. For example:


struct complex
{
int imag;

float real;
};

struct number
{
struct complex comp;

int integers;
} num1, num2;
Suppose, you want to set imag of num2 variable to 11. Here's how you can do it:

num2.comp.imag = 11;

3.3.4.6. Size of structures in C (padding and alignment in struct)

What we know is that the size of a struct is the sum of all the data members. Like for the
following struct,

struct A{
int a;
int* b;
char c;
char *d;
102
};

Size of the struct should be sum of all the data member, which is: Size of int a+ size of
int* b +size of char c+ size of char* d

Now considering the 64-bit system,


Size of int is 4 Bytes
Size of character is 1 Byte
Size of any pointer type is 8 Bytes
(Pointer size doesn't depend on what kind of data type they are pointing too)

So the size of the struct should be: (4+8+1+8)=21 Bytes

Let's see what the compiler is giving using the sizeof() operator.

#include <stdio.h>

struct A {
int a;
int* b;
char c;
char* d;
};

int main()
{
struct A a;
printf("Size of struct A: %lu\n", sizeof(struct A));
printf("Size of object a: %lu\n", sizeof(a));
return 0;
}

Output:

Size of struct A: 32
Size of object a: 32

Oops!! The output is 32 Bytes. How is that possible?

It seems like the compiler took maximum size out of the data type and assigned the same
memory to all data types. Is it so?

Okay, it's quite like that, but not the same. Of course, the compiler adds padding and
tries to align the data members. So for the above structure, the data alignment looks like
below,
103
Above is the alignment of the structure A, and that's why the size of the struct is 32
Bytes. Also, the object a of type struct A is 32 Bytes.

How does the compiler add padding?

Now the question is how does the compiler add padding and align? The method is
compiler dependent and kind of greedy. It aligns till the boundary of maximum memory
allocated. Here we find that max memory allocated is 8 Bytes, thus all the data members
acquire 8 Bytes and the total size is 32 Bytes. Now the question is will it happen every
time similarly?

Is it like the number of data members * max datatype size?

The answer is no. Check the following structure which has the same members but the
ordering is different.

struct B{
int* b;
char c;
int a;
char *d;
};

#include <stdio.h>

struct B {
int* b;
char c;
int a;
char* d;
};

int main()
{
struct B b;
printf("Size of struct B: %lu\n", sizeof(struct B));
printf("Size of object b: %lu\n", sizeof(b));
return 0;
}

Output:

104
Size of struct B: 24
Size of object b: 24

In the above structure, we find that the size is 24 Bytes though the same data members
have been used. This is due to the change in the order of the member declaration. In this
case, the alignment and padding would be like below:

Above is the alignment for structure B and that's why size is 24 Bytes, instead of 32. We
saw that the compiler keeps aligning greedily and that's why it aligned char c & int a in
the same row. When it tried to align char* d, it could not as only 3 bytes were left. But
instead of char*, if it was char only then it would have aligned in the same line.

So, I hope it's clear how the compiler aligns a structure. A point to be noted is that the
compiler can't reorder the data members though it may have reduced size. Thus, struct A
will have size 32 Bytes, not 24 Bytes.

3.3.5 UNIONS IN C

Unions are conceptually similar to structures. The syntax to declare/define a union


is also similar to that of a structure. The only difference is in terms of storage. In
structure each member has its own storage location, whereas all members of a
union use a single shared memory location which is equal to the size of its largest
data member.
Illustration :

105
This implies that although a union may contain many members of different
types, it cannot handle all the members at the same time. A union is
declared using the union keyword:
union [union name/tag]
{
// member variables goes here
}[union variable ];

3.3.5.1 ACCESSING UNION MEMBER

Syntax for accessing any union member is similar to accessing structure members,
union test
{
int a;

float b;
char c;
}t;

t.a; //to access members a of union t

t.b; //to access members b of union t


106
t.c; //to access members c of union t

#include <stdio.h>

union item
{
int a;
char ch;
};
int main( )
{
union item it;
it.a = 12;
printf("a: %d \n", it.a);
it.ch = 'z';
printf("c: %c\n", it.ch);
// Checking for corruption in memory
printf("a: %d\n", it.a);
printf("c: %c\n", it.ch);
return 0;
}

This declares a variable it of type union item. This union contains two members
each with a different data type. However, only one of them can be used at a time.
This is due to the fact that only one memory location is allocated for all the union
variables, irrespective of their size. The compiler allocates the storage that is large
enough to hold the largest variable type in the union.
In the union declared above the member requires 4 bytes which is largest
among-st the members. Other member(ch) of the union will share the same
memory address.

Check the result when this program is executed, we see that the last printf used
to output the value of a gives unexpected result because there is no longer a
107
memory space for it. The memory reserved for this union is now assigned to ch
as it’s the last to be assigned the value (‘z’) in the code.

3.3.6 ENUMERATIONS IN C

Enumeration is a user defined datatype in C language. It is used to assign names to


the integral constants which makes a program easy to read and maintain. The
keyword “enum” is used to declare an enumeration. They are mainly used to assign
names to integral constants, the names make a program easy to read and maintain.
Here is the syntax of enum in C language,
enum enum_name{const1, const2, };
The enum keyword is also used to define the variables of enum type. There are
two ways to define the variables of enum type as follows.
enum week{sunday, monday, tuesday, wednesday, thursday, friday,
saturday};
enum week day;

Here is an example of enum program demo in C language,


#include<stdio.h>

enum week{Mon=10, Tue, Wed, Thur, Fri=10, Sat=16, Sun};


enum day{Mond, Tues, Wedn, Thurs, Frid=18, Satu=11, Sund};
int main() {
printf("The value of enum week: %d\t%d\t%d\t%d\t%d\t%d\t%d\n\n",Mon , Tue, Wed,
Thur, Fri, Sat, Sun);

printf("The default value of enum day: %d\t%d\t%d\t%d\t%d\t%d\t%d",Mond , Tues,


Wedn, Thurs, Frid, Satu, Sund);

return 0;
}

108
4. APPLY ADVANCED PROGRAMING CONCEPTS WITH C

4.1. Efficient usage of control statements

Every statement in a computer is executed based on pre-defined rules. The control flow
is also based on logic. At times, you find a necessity to execute a few customized logics.
Custom statements can be executed using control statements.

Here, the control enters the statements block and gets executed if the logic is satisfied.
Hence, they are called control statements. They are often used to determine the order in
which statements must be executed.

What Are Control Statements in C?

In simple words, Control statements in C help the computer execute a certain logical
statement and decide whether to enable the control of the flow through a certain set of
statements or not. Also, it is used to direct the execution of statements under certain
conditions.

Types of Control Statements in C

● Decision-making control statements.


● Conditional statements
● Loop control statements
● Branching statements

109
4.1.1 Decision-Making Control Statements

Simple if Statement

Simple if statements are carried out to perform some operation when the condition is only
true. If the condition of the if statement is true then the statements under the if block is
executed else the control is transferred to the statements outside the if block.

Syntax of the if statement is as given below:

Flowchart

110
Example: A C program which checks if the first number of two input numbers is greater
than the second.

If-else Statement

In some situations, you may have to execute statements based on true or false under certain
conditions, therefore; you use if-else statements. If the condition is true, then if block will be
executed otherwise the else block is executed.

Syntax of the if-else statement is as given below:

111
Flowchart

Nested if-else Statements

The nested if-else statements consist of another if or else. Therefore; if the condition of “if”
is true (i.e., an outer if) then outer if’s if block is executed which contains another if (that is
inner if) and if the condition of if block is true, statements under if block will be executed
else the statements of inner if’s “else” block will be executed.

If the outer “if” condition is not true then the outer if’s “else” block is executed which
consists of another if. The outer else’s inner if the condition is true then the statement
under outer else’s inner if is executed else the outer else’s else block is executed.

Syntax of the nested if-else statement is as given below:

112
Flowchart:

113
4.1.2 Conditional Control Statements in C

As per the value of the switch expression, the switch statement will allow multi-way
branching.

Depending on the expression, the control is transferred to that particular case label and
executes the statements under it. If none of the cases are matched with the switch
expression, then the default statement is executed.

The syntax of the switch statement is as given below:

4.1.3 Loop Control Statements in C

While Loop

A while loop is also known as an entry loop because in a while loop the condition is tested
first then the statements underbody of the while loop will be executed.

If the while loop condition is false for the first time itself then the statements under the

114
while loop will not be executed even once.

The syntax of the while loop is as given below:

Flowchart

do-while Loop

The do-while is also known as an exit loop because in the do-while loop, the statements
will be executed first and then the condition is checked.

If the condition of the while loop is true then the body of the loop will be executed again
and again until the condition is false. Once the condition is false, the control will transfer
outside the do-while loop and execute statements followed soon after the do-while loop.

The syntax of the do-while loop is as given below:

115
Flowchart:

For Loop

The for loop is also known as a pre-test loop. From the following syntax, expression1 is an
initialization, expression2 is the conditional expression and expression3 is an updation. The
variables can be initialized for the statement itself.

The syntax of the do-while loop is as given below:

116
In the for loop, expression1 is used to initialize the variable, expression2 is evaluated
and if the condition is true, then the body of the for loop will be executed and then the
statements under expression3 will be executed. This process is repeated as long as the
for loop condition is true, once the condition is false control will return to the
statements following the for loop and execute those statements.

Flowchart:

4.1.4 Branching statements


117
Overview

A branch is an instruction in a computer program that can cause a computer to begin


executing a different instruction sequence and thus deviate from its default behavior of
executing instructions in order. Common branching statements include break, continue,
return, and goto.

Branching statements allow the flow of execution to jump to a different part of the
program. The common branching statements used within other control structures
include: break, continue, return, and goto. The goto is rarely used in modular structured
programming. Additionally, we will add to our list of branching items a pre-defined
function commonly used in programming languages of: exit.

Examples

break

The break is used in one of two ways; with a switch to make it act like a case structure or
as part of a looping process to break out of the loop. The following gives the appearance
that the loop will execute 8 times, but the break statement causes it to stop during the
fifth iteration.
int counter = 0;

while (counter < 8){

printf(“%d”, counter);

if (counter == 4)

break;

counter += 1; }

continue

118
The following gives the appearance that the loop will print to the monitor 8 times, but the
continue statement causes it not to print number 4.
for (counter = 0; counter < 8; counter += 1){

if (counter == 4)

continue;

printf(“%d”, counter); }

return

The return statement exits a function and returns to the statement where the function was
called.
function (parameters’ list and their types){

statements

return <optional return value>}

goto

The goto structure is typically not accepted in good structured programming. However,
some programming languages allow you to create a label with an identifier name followed
by a colon. You use the command word goto followed by the label.
some lines of code;

goto label; // jumps to the label

some lines of code;

some lines of code;

119
some lines of code;

label: some statement; // Declared label

some lines of code;

exit

Although exit is technically a pre-defined function, it is covered here because of its common
usage in programming. A good example is opening a file and then testing to see if the file
was actually opened. If not, we have an error that usually indicates that we want to
prematurely stop the execution of the program. The exit function terminates the running of
the program and in the process returns an integer value back to the operating system. It
fits the definition of branching which is to jump to some other place in the program.

Key Terms

Branching statements Allow the flow of execution to jump to a different part of the program.
break
A branching statement that terminates the existing structure.
continue
A branching statement that causes a loop to stop its current iteration and begin the next
one.
exit
A predefined function used to prematurely stop a program and return to the operating
system.
goto
An unstructured branching statement that causes the logic to jump to a different place in
the program.
return
A branching statement that causes a function to jump back to the function that called it.

120
Exercises:

1. Write a C program to print ODD numbers from 1 to N using a while loop.


2. Write a C program to print EVEN numbers from 1 to N using a do while loop.
3. Write a C program to print all uppercase alphabets using a while loop.
4. Write a C program to print all lowercase alphabets using a while loop.
5. Write a C program to print numbers from 1 to N using a while loop.
6. Write a C program to print numbers from 1 to 10 using a while loop.
7. C program to read an integer and print its multiplication table using a for loop.

Sample output:

8. Write a C program to print tables of multiplications of numbers from 1 to 4.

Expected Output

121
122
9. C Program to check if the entered number is ZERO, POSITIVE or NEGATIVE. The program
should stop if he/she enters the character e.

10. C Program to find factorial of a number using any loop

11. C Program to find the sum of the first N natural number, N must be taken by the user.

12. Write a C program to print all prime numbers from 1 to N.

13. Write a C program to print all even and odd numbers from 1 to N.

14. Write a C program to print all Armstrong numbers from 1 to N..

15. Write a C program to print square, cube and square root of all numbers from 1 to N.

16. Write a C program to print all leap years from 1 to N.

17. Write a C program to print all upper case and lower case alphabets.

18. C program to read the age of 15 people and count total Baby age, School age and Adult age.

4.1.5 Patterns Programming in C

This the art of writing programs that generate various patterns of numbers and stars
or of any symbols. Such programs involve usage of nested for loops (a for loop inside
a for loop). A pattern of numbers, star or characters is a way of arranging these in
some logical manner or they may form a sequence. Some of these patterns are
triangles which have special importance in mathematics.
Some patterns are symmetrical while others are not.

Pattern : 1
123
#include<stdio.h>
int main(){
int i,j;

for (i=0; i<5; i++) {


for (j=0; j<5; j++) {
printf(" * ");
}
printf("\n"); }

return 0;
}

Pattern : 2

Program 2:
#include<stdio.h>
int main(){
int i,j;

for (i=0; i<5; i++) {


for (j=0; j<=i; j++) {
printf("* ");
}
printf(" \n ");
}

124
return 0;
}
Pattern : 3

Program 3:
#include<stdio.h>
void main(){
int i,j,k;
for (i=1; i<=5; i++) {
for (j=5; j>=i; j--) {
printf(" ");
}
for (k=1; k<=i; k++) {

printf("* ");
}
printf("\n");
}

Pattern : 4

Program 5:
#include <stdio.h>
int main() {
int i,j,k, rows=5;
125
// first loop for printing all rows
for ( i = 0; i < rows; i++) {

// first inner loop for printing white spaces


for ( j = 0; j < 2 * i; j++) {
printf(" ");
}

// second inner loop for printing star *


for ( k = 0; k < rows - i; k++) {
printf("* ");
}
printf("\n");
}
return 0;
}
Pattern : 5

Program5:
#include <stdio.h>
int main() {
int i,j,k, rows=5;
// first loop to print all rows
for (i = 0; i < rows; i++) {

// first inner loop to print the * in each row


for ( j = 0; j < rows - i; j++) {
printf("* ");
}
printf("\n");

126
}
return 0;
}
Pattern 6:

Program 6:
#include <stdio.h>
int main() {
int i,j,k, rows=5;
// first loop for printing all rows
for ( i = 0; i < rows; i++) {

// first inner loop for printing leading white


// spaces
for ( j = 0; j < 2 * i; j++) {
printf(" ");
}

// second inner loop for printing stars *


for ( k = 0; k < 2 * (rows - i) - 1; k++) {
printf("* ");
}
printf("\n");
}
return 0;
}

Pattern 7:

127
Program 7:
#include <stdio.h>
int main() {
int i,j,k, rows=5;
// first outer loop to iterate through each row
for ( i = 0; i < rows; i++) {

// first inner loop to print white spaces


for ( j = 0; j < rows - i - 1; j++) {
printf(" ");
}

// second inner loop to print * star in each row


for ( k = 0; k < rows; k++) {
printf("* ");
}
printf("\n");
}
return 0;
}
Pattern 8:

Program 8:
128
#include <stdio.h>
int main() {
int i,j,k, n=5;
// first outer loop to iterate through each row
for ( i = 0; i < 2 * n - 1; i++) {

// assigning values to the comparator according to


// the row number
int comp;
if (i < n) {
comp = 2 * (n - i) - 1;
}
else {
comp = 2 * (i - n + 1) + 1;
}

// first inner loop to print leading whitespaces


for ( j = 0; j < comp; j++) {
printf(" ");
}

// second inner loop to print stars *


for ( k = 0; k < 2 * n - comp; k++) {
printf("* ");
}
printf("\n");
}
return 0;
}
Pattern 9:

129
Program 9:
#include <stdio.h>
int main() {
int rows = 5,i,j,k;

// first outer loop to iterate each row


for ( i = 0; i < 2 * rows - 1; i++) {

// assigning comparator
int comp;
if (i < rows) {
comp = 2 * i + 1;
}
else {
comp = 2 * (2 * rows - i) - 3;
}

// first inner loop to print leading spaces


for ( j = 0; j < comp; j++) {
printf(" ");
}

// second inner loop to print star *


for ( k = 0; k < 2 * rows - comp; k++) {
printf("* ");
}

130
printf("\n");
}
return 0;
}

Pattern 10:

Program 10:
#include <stdio.h>
int main() {
int rows = 5,i,j,k;

// outer loop to iterator through each row


for ( i = 0; i < rows; i++) {

// inner loop to print * star in each row


for ( j = 0; j < rows; j++) {
// statement to check boundry condition
if (i > 0 && i < rows - 1 && j > 0
&& j < rows - 1) {
printf(" ");
}
else {
printf("* ");
}
}
printf("\n");
}
return 0;
}
131
Pattern 11:

Program 11:
#include <stdio.h>
int main() {
int rows = 5,i,j,k;

// first outer loop to iterate through each loop


for ( i = 0; i < rows; i++) {

// first inner loop to print leading whitespaces


for ( j = 0; j < 2 * (rows - i) - 1; j++) {
printf(" ");
}

// second inner loop to print stars * and inner


// whitespaces
for ( k = 0; k < 2 * i + 1; k++) {
if (k == 0 || k == 2 * i || i == rows - 1) {
printf("* ");
}
else {
printf(" ");
}
}
printf("\n");
}
return 0;
}

132
Pattern 12:

Program 12:
#include <stdio.h>
int main() {
int rows = 5,i,j,k;

// first loop iterating through each row


for ( i = 0; i < rows; i++) {

// first inner loop to print leading white space


for ( j = 0; j < 2 * i + 1; j++) {
printf(" ");
}

// second inner loop to print star* and hollow white


// space
for ( k = 0; k < 2 * (rows - i) - 1; k++) {
if (k == 0 || k == 2 * (rows - i) - 2 || i == 0)
printf("* ");
else {
printf(" ");
}
}
printf("\n");
}
return 0;
}

Pattern 13:
133
Program 13:
#include <stdio.h>
int main() {
int n = 5,i,j,k;

// first outer loop to iterator through each row


for ( i = 0; i < 2 * n - 1; i++) {
// assigning values to the comparator according to
// the row number
int comp;
if (i < n) {
comp = 2 * (n - i) - 1;
}
else {
comp = 2 * (i - n + 1) + 1;
}

// first inner loop to print leading whitespaces


for ( j = 0; j < comp; j++) {
printf(" ");
}

// second inner loop to print star * and inner


// whitespaces
for ( k = 0; k < 2 * n - comp; k++) {
if (k == 0 || k == 2 * n - comp - 1) {

134
printf("* ");
}
else {
printf(" ");
}
}
printf("\n");
}
return 0;
}

Pattern 14:

Program 14:
#include <stdio.h>
int main() {
int n = 5,i,j,k;

// first outer loop to iterate through each row


for ( i = 0; i < 2 * n - 1; i++) {

// assigning comparator
int comp;
if (i < n) {
comp = 2 * i + 1;
}
else {

135
comp = 2 * (2 * n - i) - 3;
}

// first inner loop to print leading whitespaces


for ( j = 0; j < comp; j++) {
printf(" ");
}

// second inner loop to print star * and inner


// whitespaces
for ( k = 0; k < 2 * n - comp; k++) {
if (k == 0 || k == 2 * n - comp - 1 || i == 0
|| i == 2 * n - 2) {
printf("* ");
}
else {
printf(" ");
}
}
printf("\n");
}
return 0;
}
Pattern 15:

Program 15:
#include <stdio.h>
int main() {

int rows = 4;

136
int n = 1;
int i,j;

// outer loop to print all rows


for ( i = 0; i < rows; i++) {

// innter loop to print abphabet in each row


for ( j = 0; j <= i; j++) {
printf("%d ", n++);
}
printf("\n");
}
return 0;
}

Pattern 16: Pascal’s Triangle in C

Program 16:
#include<stdio.h>
void main(){
int height, c,r, pt[10][10];
printf("Enter the height of triangle: ");
scanf("%d",&height);
for(r=0;r<height;r++){
for(c=0;c<height;c++){
if(c<=r){
if(c==r)
pt[r][c]=1;
else

137
pt[r][c]=pt[r-1][c]+pt[r-1][c-1];
printf(" %d ", pt[r][c]);
}
}
printf("\n");
}
}

4.2. Efficient usage of functions and pointers

4.2.1. Function Pointer in C

As we know that we can create a pointer of any data type such as int, char, float, we can
also create a pointer pointing to a function. The code of a function always resides in
memory, which means that the function has some address. We can get the address of
memory by using the function pointer.

Example:

Output:

In the above output, we observe that the main() function has some address. Therefore, we
conclude that every function has some address.

4.2.1.1. Function Pointer Declaration

Till now, we have seen that the functions have addresses, so we can create pointers that can
contain these addresses, and hence can point them.

Syntax of function pointer

return_type (*ptr_name)(type1, type2…);

Examples:

int (*ip)(int,int);
138
In the above declaration, *ip is a pointer that points to a function which returns an int value
and accepts two integer values as arguments.

foat (*fp)(float);

In this declaration, *fp is a pointer that points to a function that returns a float value and
accepts a float value as an argument.

4.2.1.2. Calling a Function through a function Pointer

Suppose we declare a function as given below:

float func(int , int); // Declaration of a function.

Calling an above function using a usual way is given below:

result = func(a , b); // Calling a function using usual ways.

Calling a function using a function pointer is given below:

result = (*fp)( a , b); // Calling a function using function pointer.

Or

result = fp(a , b); /* Calling a function using function pointer, and indirection
operator can be removed.*/

The effect of calling a function by its name or function pointer is the same. If we are
using the function pointer, we can omit the indirection operator as we did in the
second case. Still, we use the indirection operator as it makes it clear to the user that
we are using a function pointer.

Here are interesting usages of function pointers:

1. Unlike normal pointers, a function pointer points to code, not data. Typically a
function pointer stores the start of executable code.
2. Unlike normal pointers, we do not allocate or de-allocate memory using function
pointers.
3. A function’s name can also be used to get functions’ addresses. For example, in the
below program, we have removed the address operator ‘&’ in assignment. We have
also changed function call by removing *, the program still works.

139
Output:

4. Like normal pointers, we can have an array of function pointers. Below example in
point 5 shows syntax for array of pointers.
5. Function pointer can be used in place of a switch case. For example, in the below
program, the user is asked for a choice between 0 to 2 to do different tasks.

140
Sample output

6. Like normal data pointers, a function pointer can be passed as an argument and
can also be returned from a function.

For example, consider the following C program where wrapper() receives a void
fun() as parameter and calls the passed function.

141
This point in particular is very useful in C. In C, we can use function pointers to
avoid code redundancy. For example a simple qsort() function can be used to sort
arrays in ascending order or descending or by any other order in case of array of
structures. Not only this, with function pointers and void pointers, it is possible to
use qsort for any data type.

142
The output is

Similar to qsort(), we can write our own functions that can be used for any data
type and can do different tasks without code redundancy. Below is an example
search function that can be used for any data type. In fact we can use this search
function to find close elements (below a threshold) by writing a customized
compare function.

143
#include <stdio.h>

#include <stdbool.h>

// A compare function that is used for searching an integer

// array

bool compare (const void * a, const void * b)

return ( *(int*)a == *(int*)b );

// General purpose search() function that can be used

// for searching an element *x in an array arr[] of

// arr_size. Note that void pointers are used so that

// the function can be called by passing a pointer of

// any type. ele_size is size of an array element

int search(void *arr, int arr_size, int ele_size, void *x,

bool compare (const void * , const void *))

// Since char takes one byte, we can use char pointer

// for any type/ To get pointer arithmetic correct,

// we need to multiply index with size of an array

// element ele_size

char *ptr = (char *)arr;

int i;

for (i=0; i<arr_size; i++)

if (compare(ptr + i*ele_size, x))

144
return i;

// If element not found

return -1;

int main()

int arr[] = {2, 5, 7, 90, 70};

int n = sizeof(arr)/sizeof(arr[0]);

int x = 7;

printf ("Returned index is %d ", search(arr, n,

sizeof(int), &x, compare));

return 0;

Output:

The above search function can be used for any data type by writing a separate
customized compare().

7. Many object oriented features in C++ are implemented using function pointers in C.

4.2.2 Function returning a pointer

C also allows to return a pointer from a function. To do so, you would have to declare
a function returning a pointer as in the following example:

dataType *functionName(list of parameters and their types) {

}
145
From the syntax above, functionName returns a pointer to dataType.

But it is not recommended to return the address of a local variable outside the
function as it goes out of scope after function returns.

Learning unit 4, Learning outcome 2

4.2.3 Create your own header file in C and add user defined functions

As we all know that files with .h extension are called header files in C. These header
files generally contain function declarations which can be used in our main C
program, like for e.g. there is need to include stdio.h in our C program to use
function printf() in the program. So the question arises, is it possible to create your
own header file? The answer to the above is yes. header files are simply files in which
you can declare your own functions that you can use in your main program or these
can be used while writing large C programs.

NOTE:Header files generally contain definitions of data types, function prototypes


and C preprocessor commands.

Below is the short example of creating your own header file and using it accordingly.

1. Creating myHeadFile.h : Write the below code and then save the file as
myHeadFile.h or you can give any name but the extension should be .h indicating
its a header file.

2. Including the .h file in other program : Now as we need to include stdio.h as


#include in order to use printf() function. We will also need to include the above
header file myHeaderFile.h as #include”myHeaderFile.h”. The ” ” here are used to
instruct the preprocessor to look into the present folder and into the standard
folder of all header files if not found in the present folder. So, if you wish to use
146
angular brackets instead of ” ” to include your header file you can save it in the
standard folder of header files otherwise. If you are using ” ” you need to ensure
that the header file you created is saved in the same folder in which you will save
the C file using this header file.
3. Using the created header file :

Sample output

4.3.Precise usage of C structures (covered)


147
4.4.Adequate implementation of basic data structures (covered)

4.4.1. Arrays in C (Covered)

4.4.2. Linked lists

Introduction

A linked list is a data structure that consists of a sequence of nodes, where each node
contains a value and a pointer to the next node in the sequence. In C, you can
implement a linked list using structures and pointers.

To start, you would define a structure to represent a node in the linked list. This
structure would typically contain two members: one to hold the value of the node and
another to hold a pointer to the next node. Here's an example:
struct Node {
int data;
struct Node* next;
};
In this example, data represents the value stored in the node, and `next` is a pointer to
the next node in the list.
To create a linked list, you would declare a pointer to the first node, often called the
"head" of the list. Initially, the head would be set to `NULL` to indicate an empty list.
Here's an example:
struct Node* head = NULL;
To add a new node to the list, you would allocate memory for a new node using the
`malloc` function, assign the value to the `data` member, and update the `next` pointer
accordingly. Here's an example of adding a node to the beginning of the list:
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = 42;
newNode->next = head;
head = newNode;
To traverse the linked list, you would start at the head and follow the `next` pointers
until you reach the end of the list. Here's an example of printing the values of all nodes
in the list:
struct Node* current = head;
148
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
Remember to free the memory allocated for the nodes when you're done with the linked
list to avoid memory leaks. You can do this by traversing the list and using the `free`
function to deallocate each node.
This is just a basic overview of implementing a linked list in C. There are many
variations and additional operations you can perform on a linked list, such as inserting
or deleting nodes at specific positions. Let me know if you'd like more information on
any specific aspect!

Types of linked list

There are several types of linked lists, including:

1. Singly Linked List: In this type of linked list, each node contains a data element
and a reference (or link) to the next node in the sequence.
2. Doubly Linked List: In a doubly linked list, each node has two references - one to
the previous node and one to the next node. This allows for traversal in both directions.
3. Circular Linked List: In a circular linked list, the last node of the list points back to
the first node, creating a circular structure. This allows for continuous traversal of the
list.
4. Skip List: A skip list is a type of linked list that allows for faster searching by
including multiple layers of linked lists with different skip distances.
These are some of the commonly used types of linked lists, each with its own
advantages and use cases.

Linked list implementations in C

1. Singly linked list

149
Here's an example of a singly linked list implementation in C language:

This implementation creates a singly linked list and inserts nodes at the beginning of
the list. The insertAtBeginning() function is used to insert a new node with the given
data at the beginning of the linked list. The printList() function is used to print the
elements of the linked list. In the main function, we initialize an empty linked list,
insert nodes, and then print the linked list.
Output

150
2. Doubly Linked List

Here's an example of a doubly linked list implementation in C language:

This is a basic implementation of a doubly linked list in C. It includes functions to


insert a node at the beginning and display the elements of the list.
Output:
151
3. Circular Linked List

Here's an example of a circular linked list implementation in C language:

152
This implementation creates a circular linked list where the last node points back to the
head node. The insert() function inserts a new node at the beginning of the list, and the
display() function prints the elements of the circular linked list.
Output:

4.5.Proper processing of file based C program

In programming, we may require some specific input data to be generated several


numbers of times. Sometimes, it is not enough to only display the data on the console.
The data to be displayed may be very large, and only a limited amount of data can be
displayed on the console, and since the memory is volatile, it is impossible to recover the
programmatically generated data again and again. However, if we need to do so, we may
store it onto the local file system which is volatile and can be accessed every time. Here
comes the need of file handling in C.

File handling in C enables us to create, update, read, and delete the files stored on the
local file system through our C program. The following operations can be performed on a
153
file.

● Creation of the new file

● Opening an existing file

● Reading from the file

● Writing to the file

● Deleting the file

4.5.1. Needs of file handling in C

● Reusability: The data stored in the file can be accessed, updated, and deleted anywhere
and anytime providing high reusability.

● Portability: Without losing any data, files can be transferred to another in the computer
system. The risk of flawed coding is minimized with this feature.

● Efficient: A large amount of input may be required for some programs. File handling allows
you to easily access a part of a file using few instructions which saves a lot of time and
reduces the chance of errors.

● Storage Capacity: Files allow you to store a large amount of data without having to worry
about storing everything simultaneously in a program.

4.5.2. Types of files in C

1. Text Files

A text file contains data in the form of ASCII characters and is generally used to store a stream of
characters.

2. Binary Files

A binary file contains data in binary form (i.e. 0’s and 1’s) instead of ASCII characters. They
contain data that is stored in a similar manner to how it is stored in the main memory.

● The binary files can be created only from within a program and their contents can only
be read by a program.
● More secure as they are not easily readable.
154
● They are generally stored with .bin file extension.

Creating (or) Opening a file

To create a new file or open an existing file, we need to create a file pointer of FILE type.
Following is the sample code for creating file pointer.

File *f_ptr ;
We use the pre-defined method fopen() to create a new file or to open an existing file.
There are different modes in which a file can be opened. Consider the following code...

File *f_ptr ;
*f_ptr = fopen("abc.txt", "w") ;
The above example code creates a new file called abc.txt if it does not exist otherwise it is
opened in writing mode.

In C programming language, there different modes are available to open a file and they are
shown in the following table.

S. No. Mode Description

1 r Open a text file in reading mode.

2 w Open a text file in writing mode.

3 a Opens a text file in append mode.

4 r+ Opens a text file in both reading and


writing mode.

5 w+ Opens a text file in both reading and


writing mode. It set the cursor position to
the beginning of the file if it exists.

155
6 a+ Opens a text file in both reading and
writing mode. The reading operation is
performed from beginning and writing
operation is performed at the end of the
file.

Reading from a file


The reading from a file operation is performed using the following pre-defined file handling
methods.

1. getc()

2. getw()

3. fscanf()

4. fgets()

5. fread()

getc( *file_pointer ) - This function is used to read a character from a specified file which is
opened in reading mode. It reads from the current position of the cursor. After reading the
character the cursor will be at the next character.

OUTPUT:

156
getw( *file_pointer ) - This function is used to read an integer value from the specified file
which is opened in reading mode. If the data in the file is set of characters then it reads ASCII
values of those characters.

Example Program to illustrate getw() in C.

OUTPUT

fscanf( *file_pointer, typeSpecifier, &variableName ) - This function is used to read


multiple data type values from a specified file which is opened in reading mode.
157
Example Program to illustrate fscanf() in C.

OUTPUT

fgets( variableName, numberOfCharacters, *file_pointer ) - This method is used for


reading a set of characters from a file which is opened in reading mode starting from the
current cursor position. The fgets() function reading terminates with reading NULL
character.

Example Program to illustrate fgets() in C.

158
OUTPUT

fread(): The fread() function in C reads the block of data from the stream. This function first,
reads the count number of objects, each one with a size of size bytes from the given input
stream.

The total amount of bytes reads if successful is (size*count). According to the no. of
characters read, the indicator file position is incremented. If the objects read are not trivially
copy-able, then the behavior is undefined and if the value of size or count is equal to zero,
then this program will simply return 0.

Example Program to illustrate fread() in C.


159
References:

1. https://bournetocode.com/projects/GCSE_Computing_Fundamentals/pages/3-1-1-
rep_alg.html
2. https://www.bbc.co.uk/bitesize/guides/zpp49j6/revision/2#:~:text=There%20are
%20two%20main%20ways,be%20represented%20%E2%80%93%20pseudocode%20and
%20flowcharts%20.
3. https://byjus.com/gate/size-of-data-types-in-c/
4. https://www.programiz.com/c-programming
5. https://www.includehelp.com/c/size-of-struct-in-c-padding-alignment-in-struct.aspx
6. https://www.geeksforgeeks.org/pattern-programs-in-c/
7. https://www.educba.com/patterns-in-c-programming/
8. https://www.programiz.com/c-programming/examples/pyramid-pattern

160

You might also like