0% found this document useful (0 votes)
37 views71 pages

Introduction to C Programming

The document is a comprehensive guide on C programming, covering essential topics such as computer components, programming basics, variables, expressions, conditionals, loops, arrays, and functions. Each section includes solved problems and exercise problems to reinforce learning. It aims to equip readers with the foundational skills necessary for programming and problem-solving using C.

Uploaded by

sahilsinghroman
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views71 pages

Introduction to C Programming

The document is a comprehensive guide on C programming, covering essential topics such as computer components, programming basics, variables, expressions, conditionals, loops, arrays, and functions. Each section includes solved problems and exercise problems to reinforce learning. It aims to equip readers with the foundational skills necessary for programming and problem-solving using C.

Uploaded by

sahilsinghroman
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 71

C the Code

Partha Bhowmick
Professor
CSE Department, IIT Kharagpur
http://cse.iitkgp.ac.in/~pb

August 26, 2024


2

©Partha Bhowmick
Contents

1 Introduction 5
1.1 Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Components of a computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 Algorithm and flowchart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 Computer program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.5 Exercise problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2 Variables and expressions 9


2.1 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4 Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5 Operands, operators, expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.6 Precedence of arithmetic operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.7 Type casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.8 Types of expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.9 Solved problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.10 Exercise problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

3 Conditionals 23
3.1 Solved problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.2 Exercise problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

4 Loops 31
4.1 Syntax of while loop and do-while loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2 Syntax of for loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.3 break and continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.4 Nested loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.5 Solved problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.6 Exercise problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

3
4 Contents

5 One-dimensional arrays 41
5.1 What is array? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
5.2 Why array? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
5.3 Declaring arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.4 Initializing arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.5 Accessing and working with arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.6 Solved problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.7 Exercise problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

6 Functions 51
6.1 What is function? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6.2 Why function? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6.3 Defining a function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6.4 Recursive function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.5 The return statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.6 Local and global variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
6.7 Scope of a variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
6.8 Parameter passing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6.8.1 Passing by value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6.8.2 Passing by reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6.9 Passing an array to a function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6.10 More on recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6.11 Macros (#define) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
6.12 #define with arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.13 Extra topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.13.1 Generating random input using rand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.13.2 main() with arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.14 Solved problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
6.15 Exercise problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

©Partha Bhowmick
1 | Introduction

1.1 Computer
Computers have changed our world, making it easier to work, learn, and play. At the heart of every
computer is programming, which tells the computer what to do. Programming turns ideas into instructions
that computers can follow, enabling amazing things in science, medicine, and everyday life. As we dive into
C programming, we will learn the basics that allow these incredible machines to solve problems, run apps,
and power the digital world. Understanding programming is like unlocking a superpower, giving you the
skills to create and innovate with technology.
A computer is a rapidly evolving machine engineered to process data and extract information. The
processing is done according to a given sequence of instructions called a program or code. These programs
enable computers to perform a wide range of computational tasks. More importantly, many of these tasks
are performed at lightning speed—much faster than even the most brilliant minds—such as adding a million
numbers in less than a millisecond!

1.2 Components of a computer


All computations in a computer are carried out through arithmetic and logical operations, based on Boolean
logic and the binary number system. And all kinds of data in a computer—whether numbers or text or image
or audio-video signal—are stored in a computer just as binary numbers or binary strings. To store data and
to process them, the following components are required for manufacturing a computer system (Figure 1.1).
1. Computer hardware: Includes the physical parts of a computer, which are as follows.
(a) Central Processing Unit (CPU) with a microprocessor that carries out all arithmetic and logical
operations, and with a control unit to arrange the order of operations as the need be.

Monitor Computer
drwxrwxr-x 5 root root 4096 2008-07-23 02:32 kernel
drwxrwxr-x 5 root root 4096 2008-07-23 02:15 lib
drwxrwxr-x 2 root root 4096 2008-07-23 02:15 mm
drwxrwxr-x 41 root root 4096 2008-07-23 02:33 net
drwxrwxr-x 9 root root 4096 2008-07-23 02:12 scripts
drwxrwxr-x 4 root root 4096 2008-07-23 02:15 security
drwxrwxr-x 18 root root 4096 2008-07-23 02:15 sound
drwxrwxr-x 2 root root 56 2008-07-23 02:12 usr
-rw-r--r-- 1 root root 466 2008-07-23 02:33 ..tmp_kallsyms1.o.cmd
-rw-r--r-- 1 root root 466 2008-07-23 02:33 ..tmp_kallsyms2.o.cmd
-rw-r--r-- 1 root root 634 2008-07-23 02:33 ..tmp_vmlinux1.cmd
-rw-r--r-- 1 root root 650 2008-07-23 02:33 ..tmp_vmlinux2.cmd
-rw-r--r-- 1 root root 41410 2008-07-23 02:32 .config
-rw-r--r-- 1 root root 40956 2008-07-23 02:12 .config.old
-rw-rw-r-- 1 root root 572 2008-02-25 17:59 .gitignore
-rw-rw-r-- 1 root root 3657 2008-02-25 17:59 .mailmap
-rw-r--r-- 1 root root 70 2008-07-23 02:32 .missing-syscalls.d
-rw-r--r-- 1 root root 851087 2008-07-23 02:33 .tmp_System.map
-rw-r--r-- 1 root root 1244271 2008-07-23 02:33 .tmp_kallsyms1.S
-rw-r--r-- 1 root root 309464 2008-07-23 02:33 .tmp_kallsyms1.o
-rw-r--r-- 1 root root 1244271 2008-07-23 02:33 .tmp_kallsyms2.S
-rw-r--r-- 1 root root 309464 2008-07-23 02:33 .tmp_kallsyms2.o
-rwxr-xr-x 1 root root 4932528 2008-07-23 02:33 .tmp_vmlinux1
-rwxr-xr-x 1 root root 5129136 2008-07-23 02:33 .tmp_vmlinux2
-rw-r--r-- 1 root root 2 2008-07-23 02:33 .version
-rw-r--r-- 1 root root 638 2008-07-23 02:33 .vmlinux.cmd
-rw-rw-r-- 1 root root 18693 2008-02-25 17:59 COPYING
-rw-rw-r-- 1 root root 91435 2008-02-25 17:59 CREDITS
-rw-rw-r-- 1 root root 1530 2008-02-25 17:59 Kbuild
-rw-rw-r-- 1 root root 89876 2008-02-25 17:59 MAINTAINERS
-rw-rw-r-- 1 root root 50404 2008-02-25 17:59 Makefile
-rw-r--r-- 1 root root 182981 2008-07-23 02:33 Module.symvers
-rw-rw-r-- 1 root root 16930 2008-02-25 17:59 README
-rw-rw-r-- 1 root root 3119 2008-02-25 17:59 REPORTING-BUGS

Printer
-rw-r--r-- 1 root root 851087 2008-07-23 02:33 System.map
-rwxr-xr-x 1 root root 5129136 2008-07-23 02:33 vmlinux
root@rainbird:/usr/src/linux-2.6.22.19# _

Mouse
Keyboard

Figure 1.1: An example of a desktop computer system (source: wiki).

5
6 Chapter 1. Introduction

(b) Memory Unit consisting of the following types:


i. Random Access Memory (RAM), also known as primary memory or main memory or simply
memory. Anywhere if you get just the term ‘memory’, know that it is RAM.
ii. Secondary memory, also known as hard disk.
iii. Tertiary memory, such as an external disk or a pen-drive.
(c) Input devices, such as keyboard, mouse, and joystick.
(d) Output devices, such as monitor or display screen, speakers, printers, and plotters.
(e) Motherboard: The printed circuit board (PCB) within a computer, containing the main circuitry
where all other parts of the hardware plug into, in order to create a cohesive whole.
2. Operating system (OS) and other software: OS is the system software that manages computer hardware
and software resources, and provides necessary services to run computer programs. For hardware func-
tions related to input, output, and memory allocation, the OS acts as an intermediary between programs
and the computer hardware. A software consists of one or more computer programs along with necessary
documentation and other files.

1.3 Algorithm and flowchart


An algorithm provides a systematic method to solve a problem. It is visually represented by a flowchart
and practically implemented by a computer program. Flowchart aids programmers in grasping the logic
quickly, bypassing intricate programming details. Drawing a flowchart before writing the actual program
is a very good habit for beginners. Figure 1.2 shows a flowchart with the related algorithm and a part of
the C program needed to find and print the larger between two numbers. Another flowchart for the same
problem but with three numbers as input, is also shown in Figure 1.2. Notice that in this flowchart, no extra
variable is used but we need three comparisons. In §1.5 (Exercise), with the same input, you are asked to
construct a flowchart that will use two comparisons and one extra variable.

1.4 Computer program


A computer program is a sequence of instructions for a computer to execute. A computer program in its
human-readable form is called source code. A source code is written in a programming language (also called
high-level language or HLL), such as C, by a programmer. For example, a program a01-1.c written by you
in C language is the source code. In C language, the source code needs a compiler such as gcc to run on it,
in order to get the binary executable code (also called executable code, or simply executable, for brevity).
For example, the command gcc a01-1.c gives you the executable a.out corresponding to the source code
a01-1.c. Any executable code is basically a machine code, as it consists of machine-language instructions.
The compiler gcc that you run on any C code is just a machine code. There are several important stages
during the compilation process; the important ones are shown in Figure 1.3.
The source code a01-1.c and its executable a.out are all stored in the hard disk of your computer.
When the executable a.out is requested for execution, the operating system loads a.out from the hard disk
to the RAM and starts a process. The CPU switches to this process as soon as possible so that it can fetch,
decode, and then execute the machine-language instructions of a.out, one by one; we then say that the
process is running in the computer.

Library It contains many files written by experts. We call them header files or library files. One such
header file is stdio.h, which must be included in any C code in its first line, using the instruction
#include <stdio.h>. Any other header file, such as math.h or stdlib.h, should be included this way
in the beginning. Each header file contains detailed instructions for complicated tasks. For example, the

©Partha Bhowmick
Chapter 1. Introduction 7

Start

Read a and b
1. Read a and b scanf("%d%d", &a, &b);
Yes No 2. If (a > b) then if (a > b)
a ą b? 3. print a printf("%d", a);
4. Else else
Print a Print b 5. print b printf("%d", b);

End

Flowchart Algorithm C program

Start

Read a, b, c

Yes No
a ą b?

Yes No Yes No
a ą c? b ą c?

Print a Print c Print b Print c

End

Figure 1.2: Top: The flowchart, the related algorithm, and a part of the C program needed to find and
print the larger between two numbers, a and b.
Bottom: The flowchart to find and print the largest among three numbers.

functions scanf and printf are contained in stdio.h, and the square-root function sqrt is contained in
math.h. You have to include these library files in your C program to use their functions. For example, you
have to include stdio.h to use scanf or/and printf, by writing #include <stdio.h> in the beginning of
your code. Similarly, you you have to include math.h to use its sqrt function, by writing #include <math.h>
just after #include <stdio.h>.

1.5 Exercise problems

1. rLargest among three numberss Draw a flowchart to read three numbers and determine the largest.
You may use an extra variable but must not exceed two comparisons in total.

©Partha Bhowmick
8 Chapter 1. Introduction

e
e

d
d
de

co
co
co

e
Compiler Linker

bl
t
ce

ec

ta
ur

u
bj

ec
So

O
gcc

Ex
a01-1.c Library a.out
stdio.h, math.h, stdlib.h, etc.

Figure 1.3: The steps of compilation in C using the command gcc a01-1.c.

2. rSum of 10 numberss Draw a flowchart to read 10 numbers one by one and compute their sum. You
may use two extra variables and a maximum of 9 additions in total.

3. rLargest among 10 numberss Draw a flowchart to read 10 numbers one by one and determine the
largest. You may use two extra variables and a maximum of 9 comparisons in total.

4. rLargest and smallest among 10 numberss Draw a flowchart to read 10 numbers one by one and
determine both the largest and the smallest. You may use three extra variables and should aim to
minimize the total number of comparisons.

©Partha Bhowmick
2 | Variables and expressions

2.1 Variables

The data used by any computer program are stored in variables. A variable is identified by its four attributes:
name, type, value, address. These are explained below.
The name of a variable is written by the programmer. It can be any word or string composed of letters,
digits, and the underscore character. It must begin with either a letter or an underscore. Uppercase and
lowercase letters are treated as distinct in the C language. Here are some examples of variable names:
x, dx, y12, sum_1, _MYvar, realNum, complexNum, point, area, tax_rate, list, Set, Vector
The type of a variable is determined based on the type of data it stores. Accordingly, we have different
types of variables, which are also termed as data types. Further details are given in §2.2.
Depending on the type, a variable has a specific value within a specific domain. This value is either
assigned or computed when the program runs. To store this value in the main memory (i.e., RAM), a variable
needs some space during execution of the program. The amount of space, referred to as size, depends on
the data type of the variable. Hence, before using any variable, its type must be declared in the program.
This is called variable declaration. For example, by the declaration int a, the variable name is a and its
type is declared as an integer; hence, a space of 4 bytes will be allocated in the memory during execution of
the program. As another example, by the declaration char c, the variable c is declared as a character, and
hence a space of 1 byte will be allocated in the memory.
The address of a variable specifies its storage location in the main memory, which is settled during the
execution of the code. The address is denoted by the ampersand character, i.e., &; for example, for the
declaration int a, the address of a is denoted by &a. While reading the value of a variable for taking input
using scanf, its address is needed to store the value; that’s why in scanf the address is passed as an argument.
For example, to take as input the value of the integer variable a, we have to write scanf("%d", &a) to tell
the compiler that an integer has to be scanned in the decimal number system ("%d" means that) and stored
at the address &a.
Apart from the above-mentioned attributes, every variable has a scope and an extent in its corresponding
code. Its scope describes the part or block of code where it can be used. The extent describes its lifetime in
the execution of the code, i.e., the duration for which it has a meaningful value. The scope of a variable is
actually a property of the name of the variable, and the extent is a property of the storage location of the
variable. Scope is an important part of the name resolution of a variable. Because two variables (in the same
code) may have the same name but with different scopes. For example, a variable with the name x can be
declared and used in one for loop, and another variable with the same name x may be declared in another
for loop. They will be assigned different memory locations and will work therefore without any conflict.
There are certain reserved words, called keywords, that have predefined meanings in C. These keywords
cannot be used as variable names. They are listed in Table 2.1. Note that the keywords are all written
in lowercase only. Since uppercase and lowercase characters are not equivalent in programming language,
it is not illegal to write a variable name as an uppercase keyword. However, this is considered a poor
programming practice.

9
10 Chapter 2. Variables and expressions

Table 2.1: List of standard keywords in C language.

auto break case char const continue default do


double else enum extern float for goto if
int long register return short signed sizeof static
struct switch typedef union unsigned void volatile while

2.2 Data types

Table 2.2: Basic data types in C language.

Data type Meaning Size


char character 1 byte
short integer 2 bytes
int integer 4 bytes
long int integer 4 or 8 bytes
long long int integer 8 bytes
float real 4 bytes
double real 8 bytes
long double real 16 bytes

A handful of basic data types are defined in C language (Table 2.2). Clearly, all the above data types
basically store numbers. It should be understood that the data type char also stores just a number, which
actually represents a single character.1 Since the number of characters is limited, one byte is enough to
represent all of them in a unique manner. Unless specified as unsigned, each of the above data types is
signed. For example, the declaration unsigned int a specifies that the variable a is unsigned, i.e., all its 48
bits are used to represent its absolute value. If it is not unsigned, then its leftmost bit is used to represent
the sign and hence termed as sign bit. If the sign bit is 0, then it is a positive number, else it is negative.
In case of char, there are 8 bits; by default, it is considered unsigned, and hence its value ranges from
0000 0000 “ 0 to 1111 1111 “ 255. If it is declared as unsigned, then this range is same. However, if it
is declared as signed, e.g., signed char c, then the leftmost bit is used to fix its sign, and so its value
ranges from 1000 0000 “ ´128 to 0111 1111 “ 127. Know that the magnitude of 1000 0000 is given by
its 2’s complement as follows: 1’s complement of 1000 0000 “ 0111 1111 (by reversing each bit); now, the
2’s complement is given by adding 1 to the 1’s complement, thus giving 0111 1111 + 1 “ 1000 0000 “ 128;
taking the negative sign into account, we get ´128 in the decimal number system.
For every other basic data type, the default specifier is signed. Explicit declaration has to be done to
make it unsigned. For example, int a means a can be a positive or negative integer, and since it uses 32 bits,
its range is from ´231 to 231 ´ 1, which is ´2,147,483,648 (1 followed by 31 0’s in binary) to 2,147,483,647
(0 followed by 31 1’s in binary). If during execution of the code, the value of a goes out of this range, there
could be faulty output. If the declaration is unsigned int a, then the variable a can take only non-negative
integer values from 0 (32 0’s in binary) to 232 ´ 1 “ 4,294,967,295 (32 1’s in binary).
Apart from the above basic data types, there is also a special type specifier named void, which indicates
that no value is available. It is used to specify the data type returned by a function, which we shall see later.
1 In
this context, it should also be well-understood that all data in the computer are essentially binary numbers or binary
strings; the data may be simply a text or an image or an audio or a video or any other entity.

©Partha Bhowmick
Chapter 2. Variables and expressions 11

We also have another useful data type called pointer that can store the memory-address of any variable.
This will also be discussed later.
Using the basic data types, a programmer can obtain new data types called derived data types. These
include string, array, structure, and union, which will come up in later chapters.

2.3 Constants
Constants are broadly of two types: numeric and character. A numeric character is either integer or real.
Character constant means either a single character or a string of characters. A single character is specified
within single quotes, e.g., ’0’, ’y’, ’+’. A string is specified within double quotes. Some typical examples
are as follows.

int a = 0; // a is an integer, initialized with the value 0.


float x = 0.5, y; // x is a real number in floating-point format.
// y is also a floating-point number but not initialized.
float z = 0.123e9 // z is a floating-point number,
// initialized with 0.123 times 10 raised to the power 9.
char c = ’y’; // c is a character, initialized with the letter y.
char s[10] = "iit\0" // s is a string, initialized with "iit\0" (we’ll study it later).

Integer constants can also be written in hexadecimal number system. A hexadecimal integer must begin
with 0x or 0X and then contain one or more hex digits. The hex digits are 0 through 9 and a through f
(or A through F). The six letters a through f (or A through F) represent the decimal numbers 10 through 15,
respectively. Following are some hexadecimal numbers: 0x, 0xA, 0X2D, 0xf5a; check that their respective
values in decimal number system are 0, 10, 45, 3930.
There are also multiple ways of representing a real number. For example, 5 ˆ 104 can be represented by
any of the following floating-point constants: 50000, 5e4, 5e+4, 5E4, 5.0e+4, .5e5, 50E3, 50.E+3, 500e2.

2.4 Statements
In C language, a statement is a complete instruction that tells the computer to perform a specific task.
Statements are the building blocks of a program and typically end with a semicolon (;). Statements can
include operations like assigning values to variables, controlling the flow of execution, or calling functions.
Following are some examples.

int a = 5, b = 10; // assignment statement


float x; // declaration statement
if (a < b) { // control statement
printf("a is less than b"); // function call statement
x = a + b/2; // assignment statement
}
else{
; // null statement
}

Note that the sign of equality (=) is used to assign values to variables. Assignment is an operation, and
hence = is called the assignment operator. The left of = is termed as l -value. In x = a + b/2, the l -value
refers to the value of x. An l -value has a definite address in memory during execution. On the contrary,
whatever occurs at the right side of = is referred to as the r -value. In the last example, it corresponds to
the expression a + b/2. It has no address of its own, although the variables a and b have definite addresses
in the memory during the execution.

©Partha Bhowmick
12 Chapter 2. Variables and expressions

Types of l -value and r -value should preferably be the same; e.g., either both are integers or both are
real. If not, the type of the r -value will be converted to the type of the l -value, and then assigned to it.
Consider the following example.

double a;
a = 2*3;

In the assignment statement, the type of r -value is int because 2 and 3 are both integers, and so its value
is 6. However, since the type of l -value is double, the value stored for a is real, i.e., 6.0.
Now, consider another example:

int a;
a = 2*3.4;

Here, the type of r -value is real and the value is 6.8. But, since the type of l -value is int, so its integer part,
i.e., 6, is stored in a.

2.5 Operands, operators, expressions


An expression is an appropriate combination of variables, constants, and one or more operators. In general,
by the word ‘expression’, we mean an expression with at least one variable; an expression with no variable
at all, e.g., 2+3, is referred to as a ‘constant expression’ and seldom used in a code. An expression gets a
single numerical value when its variables are assigned appropriate values and all the necessary operations
are performed. Expressions can be of different types, as shown in Table 2.3.
An operand may be a constant or a variable or an expression. Its value can be an integer (int or
long int or long long int) or a real number (float or double or long double). It can be the ASCII
value of a character as well. For example, in ’f’+2, the operand is ’f’. Here, the English lowercase character
f is denoted precisely by ’f’ to indicate that its type is char. The value of the operand ’f’ is simply the
ASCII value of the character f. When this value is added with 2, the result will be the ASCII value of the
next-to-next lowercase character in the English alphabet, i.e., h. Similarly, ’h’-2 will give the ASCII value
of ’f’.
An operator defines the operation either on a single operand or on two operands; in the former case,
it is said to be a unary operator, while for the latter it is a binary operator. For example, ++ is a unary
operator, and + is a binary operator. In a++ or ++a, the value of the operand a increases by unity when the
operator ++ operates on a.
An expression can be used to build larger expressions. As a typical example, consider (a+b)*(--a) - 5.
It is an expression with two variables and one constant, having the operators for addition, multiplication,
decrement, and subtraction. The addition acts on two operands a and b, each being a variable. The
multiplication acts on two operands, each being an expression but not a variable. The decrement, denoted
by --, is the sole unary operator here and acts on a to decrease its value by unity. The subtraction is a
binary operation defined on the two operands, (a+b)*(--a) and 5, the first one being a typical expression
and the second being a constant. To understand how the value is computed, let us take a and b as 3 and 2
respectively. Then, the steps of computation are: (a+b)*(--a) - 5 “ (3+2)*(--3) - 5 “ (5)*(2) - 5 “
10 - 5 “ 5. In the actual process of computation in a computer, there are several other intermediate steps
involving computer memory and processing unit.

2.6 Precedence of arithmetic operators


It refers to the priority or order in which operations are performed when an expression contains multiple op-
erators. Operators with higher precedence are evaluated before those with lower precedence. The precedence

©Partha Bhowmick
Chapter 2. Variables and expressions 13

order for arithmetic operators in C (from highest to lowest) is:


1. Parentheses: (...)
2. Unary minus: e.g., -5
3. Multiplication, Division, and Modulus: *, /, %
4. Addition and Subtraction: +, -
For operators of the same priority, evaluation is from left to right as they appear. For example, a*-b+d%e-f
means a*(-b)+(d%e)-f. Parenthesis may be used to change the precedence of operator evaluation.
While working with expressions, it is the responsibility of the programmer to write an expression in the
correct form. For example, 1.0 / 3.0 * 3.0 will produce the value 0.999999, while 1.0 * 3.0 / 3.0 will
produce the value 1.000000.

2.7 Type casting


While working with numbers, you have to be careful. See the following code.

int a=10, b=4, c;


float x;
c = a / b;
x = a / b;

The value of c will be the integer obtained by dividing 10 by 4. In the integer domain, this value is the
quotient of dividing 10 by 4, and so c receives the value 2. The value of x will be the integer obtained by
dividing 10 by 4, which is 2 again, and but mapping it to the real domain gives 2.0; hence, x gets the value
2.0. By type casting, we can store the value 2.5 to x. It can be done by:
x = (float)a / b;
Since the right side is a mix of real ((float)a) and integer (b), the operation is done in the real domain.
As another example, the following code won’t produce correct output when a+b is odd.

int a, b;
scanf("%d%d", &a, &b);
avg = (a + b)/2;
printf("%f\n", avg);

The correct one will be if you write the assignment as:


avg = ((float) (a + b))/2;
or as:
avg = (a + b) / 2.0;.
There are some restrictions on typecasting. Everything cannot be typecast to anything. For example,
float or double should not be typecast to int, as a variable of type int cannot store everything that a
float or double can store. For a similar reason, a variable of type int should not be typecast to char.

2.8 Types of expressions


The type of an expression is determined by the operators used in it. For example, if b and c are two integers,
then b+c is an arithmetic expression, b<c is a relational expression, b&&c is a logical expression, whereas b&c
is a bitwise expression. Following are some important points about different types of expression.

©Partha Bhowmick
14 Chapter 2. Variables and expressions

Table 2.3: Different types of expressions.

Type of expression Operators Type of operands Value of expression


1. Arithmetic expression + - * / ++ -- integer or real integer or real
2. Relational expression < <= >= >= == != integer or real 0 or 1
3. Logical expression && || ! integer or real 0 or 1
4. Bitwise expression >> << ~ & | ^ integer integer

1. Arithmetic expression: b+c is an arithmetic expression in which the addition operator + acts on the
operands b and c. On assigning the values 2 and 3 to b and c respectively, the value of the expression
b+c becomes 5.
Although it may sound strange to one who is new to computer programming, a=b+c is also an
arithmetic expression with two operators, namely addition (+) and assignment (=). Here, the value of
the expression b+c is computed first, and that value is assigned to a, which eventually becomes the value
of the whole expression a=b+c. For example, on assigning the values 2 and 3 to b and c respectively,
the variable a gets the value 5, and hence the value of the expression a=b+c becomes 5. Note that the
value of a=b+c is same as the value of a, because in C language, due to the assignment operator, such an
expression always gets the value of the variable (i.e., operand) to the left side of the assignment operator.
It is the l -value and refers to the value of a, as explained in §2.4.
The value of an expression is important because that expression may be used as an operand in
another expression. For example, d=(a=b+c)+1 is an expression composed with the previous expression,
a=b+c. On assigning the respective values 2 and 3 to b and c, the value of a becomes 5, which means
the expression a=b+c receives the value 5, which gives 6 as the value of d, and this finally sets the value
of the whole expression d=(a=b+c)+1 to 6.
2. Relational expression: Consider the relational operator < used in the relational expression a<b. The
value of a<b will be 1 if a is less than b, and 0 otherwise.
A relational operator is used to compare an operand with another. The operand may be a variable
or a non-variable expression. For example, in the expression a != b the operand != is used between
two variables; it yields 1 if a and b are unequal, and yields 0 if not. On the contrary, in the expression
a != b*b+1, the same operand works between a variable and an expression.
3. Logical expression: Here we need to be careful — any nonzero integer means True, and only the
integer 0 means False. For example, a&&b evaluates to 0 if and only if at least one of a and b is 0. On
the contrary, a||b evaluates to 0 if and only if both a and b are 0. Equivalently, a&&b evaluates to 1 if
and only if both a and b are nonzero, whereas a||b evaluates to 1 if and only if at least one of a and b
is nonzero. The notation && denotes the logical and operator, whereas || denotes the logical or.
The notation ! denotes the logical not; it is a unary operator and hence acts on a single operand.
For example, the expression !a evaluates to 0 if and only if a is nonzero. That is, if a is any number
other than 0, then !a evaluates to 0, and it evaluates to 1 only if a is 0.
Clearly, since a logical expression basically works with the truth value of the associated operands,
the operands can be any real number.
Consider a practical expression: ((!weekday && hobby) || (weekday && study)). It has three
variables working as operands, namely weekday, hobby, and study; and it has four logical operators
in total. With weekday “ 0, hobby “ 1, study “ 0, it evaluates to (1 || 0) “ 1. With weekday “
1, 2, . . . , 6, it evaluates to 0 if study “ 0, no matter the value of hobby — can you check and argue?
4. Bitwise expression: An expression where bitwise operators are used for computation at the bit level.
It makes the computation fast. Bitwise operators work with integer -valued operands and cannot be
applied to non-integer real numbers such as float or double. The bitwise binary operators are & (and),
| (or), ^ (xor), << (left shift), and >> (right shift); the bitwise unary operator is ~ (1’s complement).

©Partha Bhowmick
Chapter 2. Variables and expressions 15

For example, a<<k means a left shift of the bits of a by k places. Say a has the value 5; so, its 8-bit
representation is 00000101; then a<<3 means a left shift of the bits of a by 3 places, appending three
0’s at the right side so that it again has 8 bits. This gives 00101000, thereby changing the value of a to
5 ˆ 23 “ 40. On the contrary, a>>3 does a right shift by 3 bits, changing the value of a to 00000000 “ 0.
Similarly, a>>1 applies a right shift by 1 bit, changing the value to 00000010 “ 2; and a>>2 applies a
right shift by 2 bits, changing the value to 00000001 “ 1. That is, bitwise left shift by k bits is equivalent
to multiplying by 2k , and bitwise right shift by k bits is equivalent to dividing by 2k .
The following code shows uses of the bitwise operators. Note that if the leftmost bit is 1, then it is
a negative number. For example, the 1’s complement of a (i.e., ~a) is a negative number. To print its
unsigned value, the format is %u. To print its signed value, the format is %d; and that value is given by
the 2’s complement of ~a, which, in turn, is given by the 1’s complement of ~a (i.e., a) plus 1.

1 #include <stdio.h>
2

3 int main() {
4 int a = 20; // 00...0 0001 0100 = 20
5 int b = 13; // 00...0 0000 1101 = 13
6

7 printf("Bitwise AND: a&b = %d\n", a&b );


// 00...0 0000 0100 = 4
8 printf("Bitwise OR: a|b = %d\n", a|b );
// 00...0 0001 1101 = 45
9 printf("Bitwise XOR: a^b = %d\n", a^b );
// 00...0 0001 1001 = 25
10 printf("1’s Complement: ~a = %u\n", ~a );
// 11...1 1110 1011
11 // = 4294967275 (unsigned)
12 printf("1’s Complement: ~a = %d\n", ~a ); // 11...1 1110 1011
13 // = -21 (2’s complement)
14 printf("Left Shift: a<<2 = %d\n", a<<2); // 00...0 0101 0000 = 80
15 printf("Right Shift: a>>2 = %d\n", a>>2); // 00...0 0000 0101 = 5
16

17 return 0;
18 }

2.9 Solved problems

1. rOne-variable integer expressionss Given an integer a, compute and print the values of the following
expressions: ´a, 2a ´ 3, 2a2 ´ 3a ´ 4.

1 #include <stdio.h>
2

3 int main(){
4 int a;
5

6 printf("Enter the value of a: ");


7 scanf("%d", &a);
8

9 printf("-a = %d\n", -a);


10 printf("2a-3 = %d\n", 2*a-3);
11 printf("2a^2-3a-4 = %d\n", 2*a*a-3*a-4);
12

13 return 0;
14 }

©Partha Bhowmick
16 Chapter 2. Variables and expressions

2. rTwo-variable integer expressionss Given two integers a and b as input, compute and print the val-
ues of the following expressions: a ` b, ´a ´ 2b ` 3, ´2ab, 1 ´ 2apb ´ 3q.

1 #include <stdio.h>
2

3 int main(){
4 int a,b;
5

6 printf("Enter the values of a and b: ");


7 scanf("%d%d", &a, &b);
8

9 printf("a+b = %d\n", a+b);


10 printf("-a-2b+3 = %d\n", -a-2*b+3);
11 printf("-2ab = %d\n", -2*a*b);
12 printf("1-2a(b-3) = %d\n", -2*a*(b-3));
13

14 return 0;
15 }

3. rLeft shifts Given two integers a and b as input, compute and print the value of 2a ` 4b without using
any multiplication.

1 #include <stdio.h>
2

3 int main(){
4 int a,b;
5

6 printf("Enter the values of a and b: ");


7 scanf("%d%d", &a, &b);
8

9 a <<= 1;
10 b <<= 2;
11

12 printf("Answer = %d.\n", a+b);


13

14 return 0;
15 }

4. rReal-domain expressionss Compute and print the values of the xy and x1 ` y1 in floating point, where
x, y are nonzero real numbers given as input. The value of the 1st expression should be printed up to
the 6th decimal place, and that of the 2nd expression up to the 3rd decimal place. For example, if x “ 2
and y “ 3, then the printed values should be 0.666667 and 0.833, respectively.

1 #include <stdio.h>
2

3 int main(){
4 float x, y, z;
5

6 printf("Enter the values of x and y: ");


7 scanf("%f%f", &x, &y);
8

9 printf("x/y = %f, 1/x + 1/y = %0.3f\n", x/y, 1/x + 1/y);

©Partha Bhowmick
Chapter 2. Variables and expressions 17

10

11 return 0;
12 }

5. rInteger-to-real maps Compute and print the values of the following expressions in floating point
(rounded off to 3rd decimal place), where a, b are positive integers given as input.
˜c 1
¸ a`b
a 1 1
a ` b, , ` .
b a b

For example, if a “ 2 and b “ 3, then the respective printed values will be 5.000, 0.667, 0.982.
As the values should be real, the computations should be in the real domain. You should use the math
library (math.h) and compile your code as follows: gcc <input file> -lm

1 #include <stdio.h>
2 #include <math.h>
3

4 int main(){
5 int a, b;
6

7 printf("Enter the values of a and b: ");


8 scanf("%d%d", &a, &b);
9

10 printf("1st expression: a+b = %0.3f\n", (float)(a+b));


11 printf("2nd expression: a/b = %0.3f\n", (float)a/b);
12 printf("3rd expression = %0.3f\n", pow(sqrt(1.0/a + 1.0/b), 1.0/(a+b)));
13

14 return 0;
15 }

6. rPre-increment and post-increments Write the new values obtained after the following statements
are executed one after the other.
int a, b, x; ÝÑ a, b, x all have ‘garbage values’
a = 10, b = 20, x; ÝÑ a gets 10, b gets 20
x = 50 + ++a; ÝÑ a = 11, x = 61 (a is first incremented and then added)
x = 50 + a++; ÝÑ x = 61, a = 12 (a is first added and then incremented)
x = a++ + --b; ÝÑ b = 19, x = 31, a = 13 (b is first decremented and then added)
x = a++ - ++a; ÝÑ x = -2, a = 15 (a++ is 13 as operand, ++a is 15 as operand)
In the last statement, there is a side effect: while calculating some values, something else get changed.
It is always better to avoid such complicated statements.

7. rOne-variable integer expressionss Given an integer a, compute and print the values of the following
expressions: ´a, 2a ´ 3, 2a2 ´ 3a ´ 4.

1 #include <stdio.h>
2

3 int main(){
4 int a;
5

6 printf("Enter the value of a: ");


7 scanf("%d", &a);
8

9 printf("-a = %d\n", -a);

©Partha Bhowmick
18 Chapter 2. Variables and expressions

10 printf("2a-3 = %d\n", 2*a-3);


11 printf("2a^2-3a-4 = %d\n", 2*a*a-3*a-4);
12

13 return 0;
14 }

8. rTwo-variable integer expressionss Given two integers a and b as input, compute and print the val-
ues of the following expressions: a ` b, ´a ´ 2b ` 3, ´2ab, 1 ´ 2apb ´ 3q.

1 #include <stdio.h>
2

3 int main(){
4 int a,b;
5

6 printf("Enter the values of a and b: ");


7 scanf("%d%d", &a, &b);
8

9 printf("a+b = %d\n", a+b);


10 printf("-a-2b+3 = %d\n", -a-2*b+3);
11 printf("-2ab = %d\n", -2*a*b);
12 printf("1-2a(b-3) = %d\n", -2*a*(b-3));
13

14 return 0;
15 }

9. rMinimum multiplicationss Given two integers a and b as input, compute and print the values of a2 b,
a2 b2 , and a2 b4 , using at most 6 multiplications for all three of them in total, without using any extra
variable, and without using the math library.

1 #include <stdio.h>
2

3 int main(){
4 int a,b;
5

6 printf("Enter the values of a and b: ");


7 scanf("%d%d", &a, &b);
8

9 a = a*a;
10 printf("Answers = %d, ", a*b);
11 b = b*b;
12 printf("%d, ", a*b);
13 b = b*b;
14 printf("%d.\n", a*b);
15

16 return 0;
17 }

10. rLeft shifts Given two integers a and b as input, compute and print the value of 2a ` 4b without using
any multiplication.

1 #include <stdio.h>
2

3 int main(){
4 int a,b;

©Partha Bhowmick
Chapter 2. Variables and expressions 19

6 printf("Enter the values of a and b: ");


7 scanf("%d%d", &a, &b);
8

9 a <<= 1;
10 b <<= 2;
11

12 printf("Answer = %d.\n", a+b);


13

14 return 0;
15 }

11. rReal-domain expressionss Compute and print the values of the xy and x1 ` y1 in floating point, where
x, y are nonzero real numbers given as input. The value of the 1st expression should be printed up to
the 6th decimal place, and that of the 2nd expression up to the 3rd decimal place. For example, if x “ 2
and y “ 3, then the printed values should be 0.666667 and 0.833, respectively.

1 #include <stdio.h>
2

3 int main(){
4 float x, y, z;
5

6 printf("Enter the values of x and y: ");


7 scanf("%f%f", &x, &y);
8

9 printf("x/y = %f, 1/x + 1/y = %0.3f\n", x/y, 1/x + 1/y);


10

11 return 0;
12 }

12. rAverages Read in three integers and print their average as a real number.

1 #include <stdio.h>
2

3 int main(){
4 int a, b, c;
5 printf("Enter three integers: ");
6 scanf("%d%d%d", &a, &b, &c);
7 printf("Average = %f\n", ((float)(a+b+c))/3);
8 return 0;
9 }

13. rArea of a triangles Read in the coordinates (as double-precision real numbers) of three points on
xy-plane, and print the area of the
atriangle formed by them.
You can use the Heron’s formula sps ´ aqps ´ bqps ´ cq, where s “ 21 pa ` b ` cq, and a, b, c denote the
lengths of three sides.
You can use sqrt function of math.h library to compute the square root, but should not use any other
function.

1 #include <stdio.h>
2 #include <math.h>
3

4 int main(){

©Partha Bhowmick
20 Chapter 2. Variables and expressions

5 double area, x1, y1, x2, y2, x3, y3, a, b, c, s;


6

7 printf("Enter the coordinates of 1st vertex: ");


8 scanf("%lf%lf", &x1, &y1); // read in double precision
9 printf("Enter the coordinates of 2nd vertex: ");
10 scanf("%lf%lf", &x2, &y2); // read in double precision
11 printf("Enter the coordinates of 3rd vertex: ");
12 scanf("%lf%lf", &x3, &y3); // read in double precision
13

14 a = sqrt((x2-x3)*(x2-x3) + (y2-y3)*(y2-y3));
15 b = sqrt((x1-x3)*(x1-x3) + (y1-y3)*(y1-y3));
16 c = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
17

18 s = (a+b+c)/2;
19 area = sqrt(s*(s-a)*(s-b)*(s-c));
20 printf("Area = %f\n", area);
21

22 return 0;
23 }

14. rCompound interests Read in the principal amount P, the interest rate R in percentage, the number
of years N, and print the compound interest C earned after N years. Read P and R as floating-point
numbers, and N as an integer. The compound interest C should be printed as the nearest whole number.
For example, if P = 100, R = 10, N = 7, then the value of C is Rs. 94.871712, which should be printed as
Rs. 95.
You can use pow function of math.h.

1 #include <stdio.h>
2 #include <math.h>
3

4 int main(){
5 float P, R, C;
6 int N;
7 printf("Enter P: ");
8 scanf("%f", &P);
9 printf("Enter R: ");
10 scanf("%f", &R);
11 printf("Enter N: ");
12 scanf("%d", &N);
13

14 C = P*pow((double)(1+R/100.0), (double)N) - P;
15 printf("Compound interest = Rs. %0.0f\n", C);
16

17 return 0;
18 }

15. rOne-variable logical expressionss Compute and print the logical value of !a, where a is any integer
given as input. You should check (and know) that !a “ 1 if and only if a “ 0. That is, !a “ 1 when
a “ 0, and !a “ 0 when a “ 1, ´1, 2, ´2, . . ..

1 #include <stdio.h>
2

3 int main(){

©Partha Bhowmick
Chapter 2. Variables and expressions 21

4 int a;
5

6 printf("Enter the value of a: ");


7 scanf("%d", &a);
8

9 printf("Logical value of !a = %d\n", !a);


10

11 return 0;
12 }

16. rMulti-variable logical expressionss Compute and print the logical values of the following expres-
sions, where a, b, c are the integers given as input.
(!a) && (!b) && c
(a && b) || (!c)

1 #include <stdio.h>
2

3 int main(){
4 int a, b, c;
5

6 printf("Enter the values of a, b, c: ");


7 scanf("%d%d%d", &a, &b, &c);
8

9 printf("Logical value of (!a) && (!b) && c = %d\n", (!a) && (!b) && c);
10 printf("Logical value of (a && b) || (!c) = %d\n", (a && b) || (!c));
11

12 return 0;
13 }

n
17. rSum of seriess Without using any loop, compute and print the value of i, where n is a positive
ř
i“1
integer given as input.

1 #include <stdio.h>
2

3 int main(){
4 int n;
5

6 printf("Enter the value of n: ");


7 scanf("%d", &n);
8 printf("Sum = %d.\n", n*(n+1)/2);
9

10 return 0;
11 }

18. rNumber of digitss Read in a positive integer n. Assume that it has at most 4 digits. Without using
any conditional such as if-else or switch-case, print its number of digits. Also, print the expression
you have used to get the answer.

1 #include <stdio.h>
2

3 int main(){

©Partha Bhowmick
22 Chapter 2. Variables and expressions

4 int n;
5 printf("Enter the value of n: ");
6 scanf("%d", &n);
7 printf("Number of digits in n = %d\n", 1 + (n>=10) + (n>=100) + (n>=1000));
8 printf("Expression used: 1 + (n>=10) + (n>=100) + (n>=1000)\n");
9 return 0;
10 }

2.10 Exercise problems


1. rMulti-variable logical expressionss Compute and print the logical values of the following expres-
sions, where a, b, c are the integers given as input.

a && (b || c)
a && ((b || c)==0)
!(a && (b || c))
(a && (b || c)) == 0
(a && (b || c)) == 1
(!a) && ((!b) || c)
((a == 1) || ((b == 0) && (c == 1))) || ((a == 0) || ((b == 1) && (c == 0)))
((0 <= a) && (a >= 10) && (11 <= b) && (b <= 20) && (15 <= a+b) && (c >= 5))

2. rRight shifts Given two integers a and b as input, compute and print the value of a2 ` 4b without
X \ X \

using division. (Observe that 2 and 4 are the respective quotients obtained when a and b are divided
Xa\ Xb\

by 2 and 4 respectively.)

3. rInteger-to-real maps Compute and print the values of the following expressions in floating point
(rounded off to 3rd decimal place), where a, b, c are integers given as input. You can use the math
library.
ˆ ˙ ?1
a b c 2 3 2 3
? ? 2 5 5
a ` 2b ` 3c, ` ` , p1.25a ` 2.75a ` 5.625a qpb {p1.25 ` c qq, 2a ` 3b ` c3 .
2 2 3 4

As the values should be real, the computations should be in the real domain. For example, if a “ 3, b “
2, c “ 1, then the value of a2 ` 2b ` 3c would be 1.500 ` 1.000 ` 0.333 “ 2.833.

4. rLargest fractions Given as input six positive integers a, b, c, d, e, f , find a/the largest among ad , eb , fc ,
using only integer computations.

5. rSum of seriess Without using any loop, compute and print the values of the following sums, where
n is a positive integer given as input.
n
ÿ n
ÿ n
ÿ
i2 , i3 , pi ` 1qpi ` 2qpi ` 3q.
i“1 i“1 i“1

©Partha Bhowmick
3 | Conditionals

Conditionals or conditional expressions are basically expressions used in codes for taking required decisions.
They have two possible constructs: (i) if or if-else and (ii) switch-case. The if construct means if
some condition is true, then do something. The if-else construct means if some condition is true, then do
something; otherwise do whatever is mentioned after else. The if-else construct can be extended to build
a logical chain of if-else, but should be carefully coded. The two curly braces, i.e., { and }, are used to
fix the logic.
Complications in the coding logic are often handled using switch-case or a combination of if-else
and switch-case constructs. In the switch-case construct, out of multiple cases, every particular case is
handled based on the value of a single expression in the argument of switch. The value of that expression
is computed only once and it is compared with the value of each case one by one. If there is a match, then
the block of code associated with only that case is executed, rest are not. The break statement breaks out
of the entire switch block. The default statement is optional, and its code is executed only if there is no
match with any case in that switch block.

Examples
1. Suppose weekday is an integer in r0, 6s, where 0 represents Sunday, 1 represents Monday, and so on.
Suppose that on Sunday, everyone wants to enjoy a movie. Its construct will be:
if (!weekday)
printf("Go for a movie!\n");
Now, suppose that movies are restricted other than on Sunday. Then its construct will be:
if (weekday)
printf("Try to avoid movies!\n");
Now, suppose that movies are prescribed on Sunday but music is prescribed for everyday. Then its
construct will be:
if (!weekday)
printf("Go for a movie or listen to music!\n");
else
printf("Avoid movie and listen to music!\n");
2. To complicate the above example, suppose that you need to write a code that will suggest for seeing a
movie on Sunday only, playing some sports on Monday, Wednesday, and Friday, going to a restaurant
on Tuesday, and visiting the library on Thursday and Saturday. Since there are several cases, they are a
little difficult to code using the if-else construct, but quite easier using switch-case, as shown below.
switch (weekday){
case 0:{
printf("It’s Sunday! Go for a movie!\n");
break;

23
24 Chapter 3. Conditionals

};
case 1: case 3: case 5:{
printf("Go for sports!\n");
break;
};
case 2: {
printf("Enjoy your favorite food in some restaurant!\n");
break;
};
default:{ // all other cases
printf("Visit the library!\n");
break;
};
} // end switch

3.1 Solved problems

1. rLarger fractions Given as input four positive integers a, b, c, d, find a/the larger between a
c and d,
b

using only integer computations.

1 #include <stdio.h>
2

3 int main(){
4 int a, b, c, d;
5

6 printf("Enter the values of a, b, c, d: ");


7 scanf("%d%d%d%d", &a, &b, &c, &d);
8

9 if(a*d < b*c)


10 printf("%d/%d is larger.\n", b, d);
11 else
12 printf("%d/%d is larger.\n", a, c);
13

14 return 0;
15 }
16

17 /* Examples:
18

19 Enter the values of a, b, c, d: 1 2 3 4


20 2/4 is larger.
21

22 Enter the values of a, b, c, d: 4 2 3 5


23 4/3 is larger. */

2. rPrime digitss User supplies a positive integer having value less than 100. Find and print its prime
digits if any. For example, in 47, the prime digit is 7.

1 #include <stdio.h>
2

3 int main(){
4 int n, a, b, k = 0; // k = no. of primes

©Partha Bhowmick
Chapter 3. Conditionals 25

6 printf("Enter the value of n: ");


7 scanf("%d", &n);
8

9 a = n/10;
10 b = n - 10*a;
11

12 printf("Prime digits:");
13

14 if ((a==2) || (a==3) || (a==5) || (a==7)){


15 k++;
16 printf(" %d", a);
17 }
18

19 if ((b==2) || (b==3) || (b==5) || (b==7)){


20 k++;
21 printf(" %d", b);
22 }
23

24 if(k>0)
25 printf(".\n");
26 else
27 printf("None.\n");
28

29 return 0;
30 }

3. rLine intersections There are two straight lines ax ` by ` c “ 0 and px ` qy ` r “ 0, where a, b, c, p, q, r


are all integers and given as input. (a) Check whether they are parallel, and if not, (b) find their point
of intersection. Its coordinates should be printed up to the 3rd decimal place (using %0.3f instead of
%f in printf). 2024S

1 #include<stdio.h>
2

3 int main(){
4 int a, b, c, p, q, r;
5 float x, y;
6

7 printf("Enter a, b, c: ");
8 scanf("%d%d%d", &a, &b, &c);
9 printf("Enter p, q, r: ");
10 scanf("%d%d%d", &p, &q, &r);
11

12 if(q*a == b*p)
13 printf("Lines are parallel.\n");
14 else{
15 x = (float)(-q*c+b*r)/(q*a-b*p);
16 y = (float)(-p*c+a*r)/(p*b-a*q);
17 printf("Point of intersection = (%0.3f, %0.3f)\n", x, y);
18 }
19

20 return 0;
21 }

©Partha Bhowmick
26 Chapter 3. Conditionals

4. rOne is sum of twos Read in three integers and print a message if any one of them is equal to the
sum of the other two.

1 #include <stdio.h>
2

3 int main() {
4 int a, b, c;
5

6 printf("Enter three integers: ");


7 scanf("%d %d %d", &a, &b, &c);
8

9 if (a == b + c) {
10 printf("a is equal to the sum of b and c.\n");
11 } else if (b == a + c) {
12 printf("b is equal to the sum of a and c.\n");
13 } else if (c == a + b) {
14 printf("c is equal to the sum of a and b.\n");
15 } else {
16 printf("None of the integers is equal to the sum of the other two.\n");
17 }
18

19 return 0;
20 }

5. rRoots of quadratic equations Read in the coefficients a, b, c of the quadratic equation ax2 `bx`c “
0, and print its roots nicely. For complex roots, print in x ` iy form.

1 #include <stdio.h>
2 #include <math.h>
3

4 int main() {
5 float a, b, c;
6 float discriminant, realPart, imaginaryPart, root1, root2;
7

8 // Read coefficients a, b, c
9 printf("Enter coefficients a, b, and c: ");
10 scanf("%f %f %f", &a, &b, &c);
11

12 // Calculate the discriminant


13 discriminant = b*b - 4*a*c;
14

15 // Check for real and different roots


16 if (discriminant > 0) {
17 root1 = (-b + sqrt(discriminant)) / (2*a);
18 root2 = (-b - sqrt(discriminant)) / (2*a);
19 printf("Root 1 = %.2f\n", root1);
20 printf("Root 2 = %.2f\n", root2);
21 }
22 // Check for real and equal roots
23 else if (discriminant == 0) {
24 root1 = root2 = -b / (2*a);
25 printf("Root 1 = Root 2 = %.2f\n", root1);
26 }

©Partha Bhowmick
Chapter 3. Conditionals 27

27 // If roots are complex


28 else {
29 realPart = -b / (2*a);
30 imaginaryPart = sqrt(-discriminant) / (2*a);
31 printf("Root 1 = %.2f + %.2fi\n", realPart, imaginaryPart);
32 printf("Root 2 = %.2f - %.2fi\n", realPart, imaginaryPart);
33 }
34

35 return 0;
36 }

6. rOperation selections Create a simple calculator program that takes two numbers and an operator
(+, -, *, /, %) as input and performs the corresponding operation using a switch-case statement.

1 #include <stdio.h>
2

3 int main() {
4 char operator;
5 float num1, num2, result;
6

7 // Read operator and two numbers


8 printf("Enter operator (+, -, *, /, %c): ", ’%’);
9 scanf(" %c", &operator);
10 printf("Enter two numbers: ");
11 scanf("%f%f", &num1, &num2);
12

13 // Perform operation based on the operator


14 switch (operator) {
15 case ’+’:
16 result = num1 + num2;
17 break;
18 case ’-’:
19 result = num1 - num2;
20 break;
21 case ’*’:
22 result = num1 * num2;
23 break;
24 case ’/’:
25 if (num2 != 0)
26 result = num1 / num2;
27 else {
28 printf("Error! Division by zero.\n");
29 return 1;
30 }
31 break;
32 case ’%’:
33 if ((int)num2 != 0)
34 result = (int)num1 % (int)num2;
35 else {
36 printf("Error! Division by zero.\n");
37 return 1;
38 }
39 break;
40 default:

©Partha Bhowmick
28 Chapter 3. Conditionals

41 printf("Invalid operator!\n");
42 return 1;
43 }
44

45 printf("Result: %.2f\n", result);


46 return 0;
47 }

7. rVowel or consonants Develop a program that takes a single character as input and determines
whether it is a vowel or a consonant using a switch-case statement.

1 #include <stdio.h>
2

3 int main() {
4 char ch;
5

6 printf("Enter a character: ");


7 scanf(" %c", &ch);
8

9 switch (ch) {
10 case ’a’:
11 case ’e’:
12 case ’i’:
13 case ’o’:
14 case ’u’:
15 case ’A’:
16 case ’E’:
17 case ’I’:
18 case ’O’:
19 case ’U’:
20 printf("%c is a vowel.\n", ch);
21 break;
22 default:
23 printf("%c is a consonant.\n", ch);
24 }
25

26 return 0;
27 }

8. rDay of the weeks Write a program that takes the day of the week as an input (1 for Monday, 2 for
Tuesday, etc.). If the day is Saturday or Sunday, print Weekend. For other days, print the name of
the day. Additionally, check if the day is a special day (e.g., Wednesday) using if-else, and print an
appropriate message.

1 #include <stdio.h>
2

3 int main() {
4 int day;
5

6 printf("Enter day of the week (1 for Monday, 7 for Sunday): ");


7 scanf("%d", &day);
8

9 switch (day) {

©Partha Bhowmick
Chapter 3. Conditionals 29

10 case 1:
11 printf("Monday\n");
12 break;
13 case 2:
14 printf("Tuesday\n");
15 break;
16 case 3:
17 printf("Wednesday\n");
18 break;
19 case 4:
20 printf("Thursday\n");
21 break;
22 case 5:
23 printf("Friday\n");
24 break;
25 case 6:
26 case 7:
27 printf("Weekend\n");
28 return 0;
29 default:
30 printf("Invalid day\n");
31 return 0;
32 }
33

34 // Additional check for special day


35 if (day == 3) {
36 printf("It’s Wednesday, halfway through the week!\n");
37 } else if (day >= 1 && day <= 5) {
38 printf("It’s a weekday.\n");
39 }
40

41 return 0;
42 }

9. rMarks to grades Suppose that you have to print the grade of a student, with 90–100 marks get-
ting EX, 80–89 getting A, 70–79 getting B, 60–69 getting C, 50–59 getting D, 40–49 getting P, and less
than 40 getting F. Read in the marks of a student and print his/her grade. You should use switch-case.

1 #include <stdio.h>
2

3 int main() {
4 int marks;
5 char grade;
6

7 // Read the student’s marks


8 printf("Enter the student’s marks: ");
9 scanf("%d", &marks);
10

11 // Determine the grade based on marks


12 switch (marks / 10) {
13 case 10: // Handles marks 100
14 case 9:
15 grade = ’E’; // For EX
16 break;

©Partha Bhowmick
30 Chapter 3. Conditionals

17 case 8:
18 grade = ’A’;
19 break;
20 case 7:
21 grade = ’B’;
22 break;
23 case 6:
24 grade = ’C’;
25 break;
26 case 5:
27 grade = ’D’;
28 break;
29 case 4:
30 grade = ’P’;
31 break;
32 default:
33 grade = ’F’;
34 }
35

36 // Print the corresponding grade


37 if (grade == ’E’) {
38 printf("Grade: EX\n");
39 } else {
40 printf("Grade: %c\n", grade);
41 }
42

43 return 0;
44 }

3.2 Exercise problems

1. rLargest fractions Given as input six positive integers a, b, c, d, e, f , find a/the largest among ad , eb , fc ,
using only integer computations.

2. rLargest elements Given as input five numbers a, b, c, d, e, find a/the largest among them using at
most four comparisons. You can use an extra variable.

3. rTemperature alert systems Create a program that takes the current temperature as input and
provides a message based on the following conditions:
• Above 100˝ F: "Heat Alert!"
• 85˝ F to 100˝ F: "Warm Weather"
• 60˝ F to 84˝ F: "Pleasant Weather"
• 32˝ F to 59˝ F: "Cool Weather"
• Below 32˝ F: "Cold Alert!"
Use if-else to evaluate the temperature and display the corresponding message.

4. rTraffic light simulations Create a program that simulates a traffic light. The program should take a
character input (’r’ or ’R’ for Red, ’y’ or ’Y’ for Yellow, ’g’ or ’G’ for Green) and display a message
indicating whether to stop, slow down, or go. Use a switch-case to handle the different light colors.

©Partha Bhowmick
4 | Loops

?
Loops are needed
? ? to perform repeated tasks of same nature. For example, to compute the value of 1 ` 2 `
3 ` ¨ ¨ ¨ ` 99, we have to compute the square root of a number, 98 times, and so a loop will be useful. A
loop essentially executes a block of code as long as a specified expression is true. The specified expression is
treated as a Boolean condition.
Loops are of three types: while loop, do-while loop, and for loop. They are all equivalent in the sense
that one can be used in place of another, but sometimes one is a little more convenient than the others while
writing the code.

4.1 Syntax of while loop and do-while loop

The general syntax of the while loop and the do-while loop are as follows. As mentioned above, the
expression written inside while(...) is treated as a Boolean condition. A loop iterates till the condition
is true.

// declare and initialize variables // declare and initialize variables


while (expression){ do{
// code block to be executed // code block to be executed
} } while (expression);

? ? ?
The above two loops for the specific problem of computing the value of 1 ` 2 ` 3 ` ¨ ¨ ¨ ` 99 are
written below. Notice that the condition for either of these two loops is i < 100, which is just an expression
(as explained earlier in Section 2.5). The value of this expression is nonzero (i.e., true) if and only if i is
less than 100. In every iteration, the value of i is increased by unity. So, here the variable i acts as the
loop variable and determines how many times the loop will iterate. Check that in this example, the loop
iterates for 98 times; and when the value of i becomes 100, it terminates. This happens for both the while
loop and the do-while loop.

int i = 1; int i = 1;
double sum = 1.0; double sum = 1.0;
while (i < 100){ do{
i++; i++;
sum += sqrt((double)i); sum += sqrt((double)i);
} } while (i < 100);

31
32 Chapter 4. Loops

4.2 Syntax of for loop


The general syntax of a for loop is given below. Here, expression 2 is treated as a Boolean con-
dition. expression 1 is used for initialization of the loop variable and of other variables if needed,
while expression 3 is usually used for modifying the value of the loop variable. During each iteration,
expression 3 is evaluated first, followed by expression 2. None of these three expressions is mandatory;
in fact, for( ; ; ) is also a valid syntax.

// declare and initialize variables if any


for (expression 1; expression 2; expression 3){
// code block to be executed
}
? ? ?
The for loop to compute 1 ` 2 ` 3 ` ¨ ¨ ¨ ` 99 is written below. Notice that the condition here is
i < 100, which is just same as in the while and the do-while loops. So, here also the variable i acts here
as the loop variable. Check that this loop iterates 98 times, as in the case of while or do-while loop.
int i;
double sum;
for (i=2, sum=1.0; i < 100; i++){
sum += sqrt((double)i);
}
With the 1st expression empty in for(...), we can rewrite the code as follows.
int i = 2;
double sum = 1.0;
for ( ; i < 100; i++){
sum += sqrt((double)i);
}
With all three expressions empty, we can rewrite the code as follows.
int i = 2;
double sum = 1.0;
for ( ; ; ){
sum += sqrt((double)i);
i++;
if(i==100)
break;
}
All three are correct, but it is a bad practice to write a for loop as the last one.

4.3 break and continue


A break statement makes the program immediately exit from a while loop, do-while loop, for loop, or a
switch-case block. Its use in switch-case is already shown in Chapter 3. On encountering a break, the
program execution resumes with the next statement following the loop or switch-case. Note that the break
statement is not applicable within if or if-else constructs.
A continue statement makes the program skip the remaining statements in the body of a while, for,
or do-while loop in the ongoing iteration. Afterward, program execution proceeds with the next iteration
of the loop. The continue statement is not used in switch-case.
A break statement or continue statement has to be used judiciously, when it is really needed. The
logical flow of the program should be well-understood for using such statements.

©Partha Bhowmick
Chapter 4. Loops 33

Examples: The following code finds the smallest number n such that n! exceeds 1000. See how it uses a
break statement.

int fact = 1, n = 1;
while(1){
fact = fact * n;
if (fact > 1000){
printf ("Factorial of %d exceeds 1000", n)
break; // breaks the while loop
}
i++ ;
}

The following code goes on adding positive integers until a 0 is encountered, ignoring all negative
numbers that appear in between. See how it uses break and continue statements.

int sum = 0, next;


while (1){
scanf("%d", &next);
if (next < 0)
continue; // scans the next element
if (next == 0)
break; // breaks the while loop
sum = sum + next;
}
printf ("Sum = %d\n", sum) ;

4.4 Nested loops


Nested loops are loops that operate within another loop, allowing for more complex iteration patterns. In
a nested loop structure, the inner loop completes all its iterations for each iteration of the outer loop. This
means that the inner loop’s execution depends on the number of iterations specified by the outer loop. For
example, if the outer loop runs m times and the inner loop runs n times, then the total number of iterations
will be mn. Nested loops are often used for tasks that require multi-dimensional iteration, such as traversing
a 2D array or matrix, where the outer loop handles the rows and the inner loop handles the columns.
While nested loops can be powerful, they can also lead to significant increase in computational complexity,
particularly if the loops are deeply nested or the iteration ranges are large. Therefore, it is important to
manage them carefully to avoid performance issues.
The following program prints a multiplication table for numbers from 10 to 20. It uses nested loops to
generate the table.

#include <stdio.h>
int main(){
int i, j;
for (i = 10; i <= 20; i++){ // outer loop
for (j = 10; j <= 20; j++){ // inner loop
printf("%3d\t", i * j);
}
printf("\n");
}
return 0;

In the outer loop, the variable i iterates from 10 to 20, representing the rows of the multiplication table.
In the inner loop, for each iteration of the outer loop, the variable j iterates from 10 to 20, representing

©Partha Bhowmick
34 Chapter 4. Loops

the columns. After the multiplication, the product of i and j is calculated and printed, with each value
separated by a tab (\t) to format the table neatly. After each row is printed, the program moves to the next
line using \n. The output looks as follows.

100 110 120 130 140 150 160 170 180 190 200
110 121 132 143 154 165 176 187 198 209 220
120 132 144 156 168 180 192 204 216 228 240
130 143 156 169 182 195 208 221 234 247 260
140 154 168 182 196 210 224 238 252 266 280
150 165 180 195 210 225 240 255 270 285 300
160 176 192 208 224 240 256 272 288 304 320
170 187 204 221 238 255 272 289 306 323 340
180 198 216 234 252 270 288 306 324 342 360
190 209 228 247 266 285 304 323 342 361 380
200 220 240 260 280 300 320 340 360 380 400

©Partha Bhowmick
Chapter 4. Loops 35

4.5 Solved problems


1. rASCII of English alphabets Print as integers (in decimal number system) the ASCII values of ’a’
to ’z’ and those of ’A’ to ’Z’. Don’t directly use in your code the value of any character.

1 #include <stdio.h>
2

3 int main(){
4

5 for (int i=0; i<26; i++)


6 printf("%c: %3d\t ", ’a’+i, ’a’+i);
7 printf("\n");
8

9 for (int i=0; i<26; i++)


10 printf("%c: %3d\t ", ’A’+i, ’A’+i);
11 printf("\n");
12

13 return 0;
14 }
See that in the expression ’a’+i, ’a’ is a character, whereas i is an integer. The operator + is used to
add the ASCII value (which is always an integer) of ’a’ with the value of i. Consequently, the value of
’a’+i is also an integer. The same holds for the expression ’A’+i as well. The overall output will be as
follows:
a: 97 b: 98 c: 99 d: 100 e: 101 f: 102 g: 103 h: 104 i: 105
j: 106 k: 107 l: 108 m: 109 n: 110 o: 111 p: 112 q: 113 r: 114
s: 115 t: 116 u: 117 v: 118 w: 119 x: 120 y: 121 z: 122

A: 65 B: 66 C: 67 D: 68 E: 69 F: 70 G: 71 H: 72 I: 73
J: 74 K: 75 L: 76 M: 77 N: 78 O: 79 P: 80 Q: 81 R: 82
S: 83 T: 84 U: 85 V: 86 W: 87 X: 88 Y: 89 Z: 90
2. rSums Given n real numbers from the keyboard, find their sum. User input is n and the numbers.

1 #include <stdio.h>
2

3 int main(){
4 int i, n;
5 float x, sum;
6

7 printf("Enter n: ");
8 scanf("%d", &n);
9

10 printf("Enter the numbers: ");


11 for (i=0, sum=0.0; i<n; i++){
12 scanf("%f", &x);
13 sum += x;
14 }
15

16 printf("Sum = %f\n", sum);


17

18 return 0;
19 }

©Partha Bhowmick
36 Chapter 4. Loops

3. rReading characterss Read in characters until the n character is typed. Count and print the number
of lowercase letters, the number of uppercase letters, and the number of digits entered.

1 #include <stdio.h>
2

3 int main() {
4 char ch;
5 int lower_count = 0, upper_count = 0, digit_count = 0;
6

7 while ((ch = getchar()) != ’\n’) {


8 if (ch >= ’a’ && ch <= ’z’) {
9 lower_count++;
10 } else if (ch >= ’A’ && ch <= ’Z’) {
11 upper_count++;
12 } else if (ch >= ’0’ && ch <= ’9’) {
13 digit_count++;
14 }
15 }
16

17 printf("Lowercase letters: %d\n", lower_count);


18 printf("Uppercase letters: %d\n", upper_count);
19 printf("Digits: %d\n", digit_count);
20

21 return 0;
22 }
n
4. r5th-power sums Given a positive integer n, compute the value of k 5 , without using math.h.
ř
k“1

1 #include <stdio.h>
2

3 int main(){
4 int k, n;
5 long long int sum;
6

7 printf("Enter n: ");
8 scanf("%d", &n);
9

10 for (k=1, sum=0; k<=n; k++){


11 sum += k*k*k*k*k;
12 }
13

14 printf("Sum = %lld\n", sum);


15

16 return 0;
17 }
5. rBit-lengths Given a positive integer n, determine the integer ` such that 2`´1 ď n ă 2` . Here, ` is
called the bit-length of n.

1 #include <stdio.h>
2

3 int main(){
4 int n, i=1, len=0;
5

©Partha Bhowmick
Chapter 4. Loops 37

6 printf("Enter an integer: ");


7 scanf("%d", &n);
8

9 while(i<=n){
10 i <<= 1; len++;
11 }
12 printf("Bit-length = %d\n", len);
13

14 return 0;
15 }
6. rDecimal to binary, 8 bitss Given an integer n P r0, 255s, print its 8-bit binary representation. You
can use at most 3 integer variables and no character variables.

1 #include <stdio.h>
2

3 int main(){
4 int n, i, j;
5

6 printf("Enter an integer in [0,255]: ");


7 scanf("%d", &n);
8 printf("Binary: ");
9

10 for (j=128; j>0; j/=2){


11 if(n/j == 1)
12 printf("1"),
13 n-=j;
14 else
15 printf("0");
16 }
17 printf("\n");
18

19 return 0;
20 }
7. rGCDs Given two positive integers a, b, compute their GCD. Use the fact that if a ď b, then
if a “ 0
"
b
gcdpa, bq “ (4.1)
gcdpb mod a, aq otherwise.
Since no function other than main() is allowed in this section, you have to do it iteratively using a loop.

1 #include <stdio.h>
2

3 int main(){
4 int a, b, c;
5 printf("\nEnter two positive integers: ");
6 scanf("%d%d", &a, &b);
7 while(a!=0){
8 c = a;
9 a = b%a;
10 b = c;
11 printf("a b c = %7d %7d %7d\n", a, b, c);
12 }
13 printf("GCD = %d\n\n", b);
14 return 0;
15 }

©Partha Bhowmick
38 Chapter 4. Loops

2 3
8. rex as a finite sums We know that in the infinite sum ex “ 1 ` x ` x2! ` x3! ` ¨ ¨ ¨ , the trailing terms
have negligible values. Given a positive value of x, compute the sum up to its nth term and return that
value as the approximate value of ex as soon as the nth term is found to be less than ε. Also print the
value of n. Needless to say, you should not use the math library.

1 /* e^x approximate value */


2

3 #include <stdio.h>
4

5 int main(){
6 double x, epsilon, ex = 1.0, current = 1.0, previous = 0.0;
7 int n = 1;
8

9 printf("Enter x: ");
10 scanf("%lf", &x);
11 printf("Enter epsilon: ");
12 scanf("%lf", &epsilon);
13

14 while(current > epsilon){


15 n++;
16 previous = current;
17 current = previous*x/(double)(n-1);
18 printf("%lf ", current);
19 ex += current;
20 }
21

22 printf("\nApproximate e^x = %lf (up to term %d)\n", ex, n);


23 return 0;
24 }
9. rInfinite sums With b P r3, 7s as the only input, do the following.
8 ` a ˘i
(a) Compute and print the values of p´1qi as fractions in increasing order, for a P r1, b ´ 1s.
ř
b
i“0
Note that there are b ´ 1 fractions, each one less than 1 because a ă b.
(b) Also compute and print the sum of the above fractions, as a simple fraction. A simple fraction is
one in which the GCD of the numerator and the denominator is 1.
1 /* sum = 1/(1+x) = 1/(1+(a/b)) = b/(a+b).*/
2

3 #include <stdio.h>
4

5 int main(){
6 int a, b, p, q, r, s, t;
7 printf("Enter b: ");
8 scanf("%d", &b);
9

10 p = b, q = 2*b-1;
11 printf("%d/%d ", b, 2*b-1);
12

13 for(a=b-2; a>0; a--){


14 printf("%d/%d ", b, a+b);
15 p = p*(a+b)+q*b; q = q*(a+b);
16 }
17

©Partha Bhowmick
Chapter 4. Loops 39

18 //To make p/q simple, divide p and q by gcd(p,q)


19 r = p, s = q;
20 while(r!=0){ // find GCD(r,s)
21 t = r;
22 r = s%r;
23 s = t;
24 } // GCD = s
25 printf("\nSum = %d/%d\n", p/s, q/s);
26 return 1;
27 }
28

10. rPrint squares Print a 5 ˆ 5 square filled up with ’*’.

1 #include <stdio.h>
2

3 int main(){
4 const int SIZE = 5;
5 int row, col;
6 for (row = 0; row < SIZE; ++row){
7 for (col = 0; col < SIZE; ++col){
8 printf("* ");
9 }
10 printf("\n");
11 }
12 return 0;
13 }
Note that const indicates that the value of SIZE cannot be modified after it is initialized. It is a constant,
so trying to change its value later in the code will result in a compilation error.
The output is shown in Figure 4.1(a).
11. rPrint lower triangles Print the lower triangle of a 5 ˆ 5 square filled up with ’*’. The output is
shown in Figure 4.1(b).

1 #include <stdio.h>
2

3 int main(){
4 const int SIZE = 5;
5 int row, col;
6 for (row = 0; row < SIZE; ++row){
7 for (col = 0; col <= row; ++col){
8 printf("* ");
9 }
10 printf("\n");
11 }
12 return 0;
13 }
12. rPrint upper triangles Print the upper triangle of a 5 ˆ 5 square filled up with ’*’. The output is
shown in Figure 4.1(c).

1 #include <stdio.h>
2

3 int main(){
4 const int SIZE = 5;

©Partha Bhowmick
40 Chapter 4. Loops

* * * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * * *
(a) square (b) lower triangle (c) upper triangle

Figure 4.1: Output of the codes for printing a square, its lower triangle, and its upper triangle.

5 int row, col;


6 for (row = 0; row < SIZE; ++row){
7 for (col = 1; col <= row; ++col)
8 printf(" ");
9 for (col = 1; col <= SIZE-row; ++col)
10 printf("* ");
11 printf ("\n");
12 }
13 return 0;
14 }

4.6 Exercise problems


1. rASCIIs Print all the characters with ASCII values from 0 to 127.
2. rmax and 2nd maxs Read in an integer n. Then read in n numbers and print their maximum and
second maximum. Assume that all numbers are distinct.
n
3. rPower sums Given a positive integer n, compute k k , without using math.h.
ř
k“1
4. rDigit counts Given any integer in decimal number system, compute its number of digits. For example,
for 3180, it is 4.
5. rPrimess Find all the prime numbers less than a given positive integer n.
6. rCo-primess Two positive integers are said to be co-prime with each other if their GCD is 1. Given a
positive integer n, find the co-primes that are all less than n. For example, for 9, they are 2, 4, 5, 7, 8.
7. rTwo-prime sums Given a positive integer n, determine whether it can be written as the sum of two
primes.
8. rsin, coss Using x as input in the double-precision format, compute and print the values of sin x and
cos x using the following equations.
8 8
ÿ p´1qn 2n`1 ÿ p´1qn 2n
sin x “ x , cos x “ x . (4.2)
n“0
p2n ` 1q! n“0
p2nq!

Use #define DIFF 0.00001 to terminate the summation when the sum up to nth term differs by less
than DIFF from the sum up to pn ´ 1qst term. Needless to say, you should not use the math library.

©Partha Bhowmick
5 | One-dimensional arrays

Suppose that you have lots of storybooks, poetry books, comic books, etc.,
and also have many other books on different subjects such as Physics, Chem-
istry, Biology, Mathematics, etc. While keeping them in a bookshelf, you will
naturally try to keep them in an organized way so that you can get any book
down from the shelf right away, whenever needed. The same idea is used
when you have to keep many elements in the computer memory. You have
to arrange them in an organized way in the memory so that any of them can
immediately be accessed when the code is running. For this arrangement, the
concept of data structure comes into use. One such data structure is array—it
is just analogous to your bookshelf!

5.1 What is array?


A data structure, often referred to as a data type in programming, is a collection of distinct or non-distinct
items arranged in a specific order. Common examples of simple data structures include lists, queues, and
stacks. Among these, the list is the simplest and can be implemented using an array or a linked list.1
An array is a data structure used to represent and store items of the same data type. This data type
can be a basic one such as char, int, or float, or it can be a user-defined data type or structure (e.g.,
struct, which will be discussed later). In fact, the items stored in an array can themselves be arrays!2
An array is similar to a set. Just as a set is a collection of items of the same type, so too is an array.
However, unlike a set, which always contains distinct items, an array does not have this restriction. When
a set A stores n items, they are typically denoted by a1 , a2 , . . . , an . Similarly, when a one-dimensional array
a[] contains n items, they are represented by a[0], a[1], . . . , a[n-1]. For any i ranging from 0 to n-1, i
is called the index of the element a[i] in the array a[]. That is, the elements a[0], a[1], . . . , a[n-1] have
indexes 0, 1, . . . , n-1, respectively. Figure 5.1 shows an example of an integer array with 5 elements. Note
that in this array, the elements at index 2 and index 4 are identical.

5.2 Why array?


First, the concept of array is useful to store in memory a large number of items of similar data type, using
a single declaration. For example, if we need 1000 integers, then we can simply declare int a[1000]; the
elements here are indexed from 0 to 999 and denoted by a[0], a[1], . . . , a[999] in the language of C. Had
the concept of array not been there, we could have no other way than to denote the 1000 integers by 1000
variables with 1000 different names—something as int a000, a001, . . . , a999—a nightmare!
1A linked list is implemented using pointers. We will explore this concept later in the course.
2 For example, a two-dimensional array is simply a one-dimensional array of one-dimensional arrays. We will study two-
dimensional arrays later. In this chapter, the term ‘array’ refers specifically to a one-dimensional or linear array.

41
42 Chapter 5. One-dimensional arrays

indexes 0 1 2 3 4
main memory (RAM) 7 ´2 6 3 6 main memory (RAM)

byte address lines

8D2C

8D30

8D34

8D38

8D3C
8D2D
8D2E
8D2F

8D31
8D32
8D33

8D35
8D36
8D37

8D39
8D3A
8D3B

8D3D
8D3E
8D3F
8D40
8D41
8D42
8D43
byte addresses
(in hexadecimal)

Figure 5.1: An array with 5 elements having values 7, ´2, 6, 3, 6. Each element is a 4-byte integer, so the
total space allocated in the memory for this array is 4 ˆ 5 “ 20 bytes. Its first and last byte have
the addresses 8D2C and 8D3F, respectively. The address of an element is basically the address
of its first byte (expressed as a hexadecimal number, a typical convention). So, the respective
addresses of the five elements here are 8D2C, 8D30, 8D34, 8D38, and 8D3C.

Second, the elements of an array occupy contiguous locations in the memory when the executable file
is executed. As a result, any element of the array can be accessed directly, just by specifying its index.
In particular, a[i] gives the element with the index i in a[]. The direct accessing is possible because the
address of the element with index i easily follows from the address of the element with index 0. The simple
reason is that all elements have the same data type and hence they all take equal amount of space (measured
in bytes) in the memory. Further, every byte in the memory has a unique address, and two contiguous bytes
have consecutive addresses. To see this, suppose that the amount of space for each element is k bytes. As
&a[0] is the address of the element with index 0, the indexes of the subsequent elements are &a[0]+k for
index 1, &a[0]+2*k for index 2, &a[0]+3*k for index 3, and so on. That is, the address of a[i] will be

&a[i] “ &a[0] + i*k.

As an example, see Figure 5.1. Here a[] is an integer array and its 1st element a[0] has the address 8D2C; so,
its 2nd element a[1] has the address 8D2C + 4 “ 8D30, 3rd element a[2] will have the address 8D2C + 2*4
“ 8D34, and so on. If b[] is an array of characters, then &b[i] “ &b[0] + i. If the 1st character of b[]
(i.e., b[0]) has the address AC8F, then its 2nd character b[1] will have the address AC8F + 1 “ AC90, its
3rd character b[2] will have the address AC8F + 2 “ AC91, and so on.
Third, the index need not be just a single variable but can also be an expression whose value is an integer
in the interval r0, n-1s, where n is the number of elements in the array. For example, in an array a[] with
100 elements, a[i+2*j] is a valid element with i and j as two integers, as long as the value of the expression
i+2*j lies in r0, 99s.
Another example could be a[b[i]], where the element b[i] of an array b[] acts as the index of an
element in the array a[]. Such kinds of indexing are sometimes required while writing codes for tricky
problems. For example, see the following code. It takes as input some integers in r0, 9s, stores them in an
array a[], and then prints them in increasing order, avoiding repetitions. It uses an additional array b[],
initialized with all zeros, to count the frequency of each distinct element stored in a[]. Since there will be
at most 10 distinct elements in a[], the size of b[] is set to 10. The trick is that b[a[i]] means how many
times an element a[i] appears in a[].

1 #include <stdio.h>
2

3 int main() {
4 int n, i, j;
5 printf("Enter the number of elements: ");
6 scanf("%d", &n);
7 int a[n], b[10];
8 for (i = 0; i < 10; i++)
9 b[i] = 0;
10

11 printf("Enter the elements (0 to 9):\n");

©Partha Bhowmick
Chapter 5. One-dimensional arrays 43

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


13 scanf("%d", &a[i]);
14

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


16 b[a[i]]++; // the trick
17

18 printf("Sorted array: ");


19 for (i = 0; i < 10; i++) {
20 if (b[i] > 0) // i appears in a[]
21 printf("%d ", i);
22 }
23 printf("\n");
24

25 return 0;
26 }
27 /*
28 Enter the number of elements: 13
29 Enter the elements (0 to 9): 5 4 7 8 4 0 4 4 0 5 7 8 7
30 Sorted array: 0 4 5 7 8
31 */

5.3 Declaring arrays


Like other variables, an array should be declared first before using it. The general syntax is

type array_name[size];

where type specifies the type of elements (char, int, float, etc.) that will be stored in the array, array_name
denotes the name of the array, and size is the maximum number of elements that can be stored in the array.
Here are some examples:

int roll_num[100]; // array name is roll_num, can store up to 100 integers


char gender[100]; // array name is gender, can store up to 100 characters
float marks[100]; // array name is marks, can store up to 100 floating-point numbers

5.4 Initializing arrays


The general form is:

type array_name[size] = {comma-separated values};

And here are some examples:

int roll_num[5] = {31, 32, 33, 34, 35};


char gender[5] = {’F’, ’M’, ’M’, ’F’, ’M’};
float marks[10] = {72.5, 83.25, 65.5, 80, 76.25};

In the above examples, all three arrays are declared to contain 5 elements each, and their values are initialized.
We can also declare them to contain more elements, say 10 each, but only the first five are initialized. Here
is how:

©Partha Bhowmick
44 Chapter 5. One-dimensional arrays

int roll_num[10] = {31, 32, 33, 34, 35};


char gender[10] = {’F’, ’M’, ’M’, ’F’, ’M’};
float marks[10] = {72.5, 83.25, 65.5, 80, 76.25};

When you partially initialize an array in C, the uninitialized elements are automatically set to 0 for numeric
arrays and ‘\0’ (null character) for character arrays. The non-initialized as well as the initialized values
can be changed later if needed. Here’s what happens in the above cases:

roll_num = {31, 32, 33, 34, 35, 0, 0, 0, 0, 0};


gender = {’F’, ’M’, ’M’, ’F’, ’M’, ’\0’, ’\0’, ’\0’, ’\0’, ’\0’};
marks = {72.5, 83.25, 65.5, 80.0, 76.25, 0.0, 0.0, 0.0, 0.0, 0.0};

5.5 Accessing and working with arrays


In order to populate or write to an array, we must use a loop, as follows.

int a[5], i;
for (i=0; i<5; i++){ // writing to a[]
scanf("%d", &a[i]);
}

Similarly, to read from the array a[], here is how:

int p;
for (i=0; i<5; i++){ // reading from a[]
p = a[i];
}

We cannot use the operator = to assign one array to another; i.e., even if a[] and b[] are two arrays of
same type and same size, then a = b; or a[] = b[]; cannot copy the elements of b[] to a[] (it will give
compilation error). For copying the elements of b[] to a[], we have to use a loop as follows:

int i;
for (i=0; i<n; i++){ // n = number of elements in a[] and in b[]
a[i] = b[i];
}

As a specific example, suppose that there are at most 100 students in a class. Now, consider the problem
of getting their marks and finding how many of them have marks above the average. Clearly, following are
there main tasks:
1. Read the marks as input and write them in an array.
2. Compute the total marks.
3. Count how many students meet the given criterion.
Clearly, Task 1 and Task 2 can be done in a single loop. But Task 3 needs an additional loop after that
because it can be done only after Task 2 is over. That is, it is impossible to write a code for this problem
using a single loop only. (Understand the importance of this observation!) The following code is written
based on this observation. Notice that for Task 1, we are writing into the array using the indexes, while for
Task 2 and Task 3, we are reading from the array using the indexes again. In either case, the integer i is
used as the index variable.

©Partha Bhowmick
Chapter 5. One-dimensional arrays 45

1 #include <stdio.h>
2 int main(){
3 int n, i, k;
4 float marks[100], total, avg;
5 printf("Enter the number of students: ");
6 scanf("%d", &n);
7 printf("Enter their marks: ");
8 for (i=0, total=0; i<n; i++){ // Task 1 and Task 2
9 scanf("%f", &marks[i]);
10 total = total + marks[i];
11 }
12 avg = total/n;
13 for (i=0, k=0; i<n; i++){ // Task 3
14 k += (marks[i] > avg) ? 1 : 0;
15 }
16 printf("Number of students above the average = %d\n", k);
17 }

5.6 Solved problems


Note the following regarding the problems stated in this section.
i. All arrays here are one-dimensional. The number of elements that an array can store, is referred to as
the size of array. However, the full array may not be used. For example, the size of an array a[] may
be 10, but we store and work with only 7 elements from a[0] to a[6], whereby a[7] to a[9] are of
no use.
ii. Unless mentioned, for an array, assume that its size is at most 1000.
iii. Unless mentioned, assume that the input elements need not be distinct.
1. rmaxs Given a positive integer n as the first input, take in as the next input n integer elements from
the user, store them in an array, and find the largest among them. The total number of comparisons
should be at most n ´ 1.

1 // Find the largest element in an array


2

3 #include <stdio.h>
4 #define SIZE 1000
5

6 int main(){
7 int a[SIZE], n, i, max;
8

9 printf("Enter n: ");
10 scanf("%d", &n);
11 printf("Enter the elements: ");
12

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


14 scanf("%d", &a[i]);
15

16 max = a[0];
17

18 for(i=1; i<n; i++)

©Partha Bhowmick
46 Chapter 5. One-dimensional arrays

19 if (max<a[i])
20 max = a[i];
21

22 printf("Max = %d\n", max);


23 return 0;
24 }
2. rCheck distinctnesss Given a positive integer n as the first input, take in as the next input n integer
elements from the user, store them in an array, and check whether all elements in that array are distinct.

1 // Check whether all elements are distinct


2

3 #include <stdio.h>
4 #define SIZE 1000
5

6 int main(){
7 int a[SIZE], n, i, j, flag = 1;
8

9 printf("Enter n: ");
10 scanf("%d", &n);
11 printf("Enter the elements: ");
12

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


14 scanf("%d", &a[i]);
15

16 for(i=1; i<n && flag; i++){


17 for(j=0; j<i && flag; j++){
18 if(a[i]==a[j]){
19 flag = 0;
20 printf("Not distinct: a[%d] = a[%d] = %d.\n", j, i, a[i]);
21 }
22 }
23 }
24

25 if(flag)
26 printf("Distinct.\n");
27

28 return 0;
29 }
3. rFibonacci sequences The Fibonacci sequence tf piq : i “ 0, 1, 2, . . .u is defined as

f p0q “ 0, f p1q “ 1, and f piq “ f pi ´ 1q ` f pi ´ 2q if i ě 2. (5.1)

Given a non-negative integer n, compute f piq for i “ 0, 1, 2, . . . , n, store them in an array of n ` 1


integers, and print the elements of this array.

1 // Fibonacci sequence
2

3 #include <stdio.h>
4 #define SIZE 1000
5

6 int main(){
7 int a[SIZE], n, i;
8

©Partha Bhowmick
Chapter 5. One-dimensional arrays 47

9 printf("Enter n: ");
10 scanf("%d", &n);
11 a[0] = 0, a[1] = 1;
12

13 for(i=2; i<=n; i++)


14 a[i] = a[i-1] + a[i-2];
15

16 printf("Fibonacci elements: ");


17 for(i=0; i<n; i++)
18 printf("%d ", a[i]);
19 printf("\n");
20

21 return 0;
22 }
4. rSelection Sort: positive elements, extra arrays Given a positive integer n as the first input, take
in as the next input n positive integers from the user and store them in an array A. Take another
array B of the same size and put the elements of A into B in non-decreasing order. For example, if
A “ r4, 2, 3, 2, 6, 4s, then B “ r2, 2, 3, 4, 4, 6s.

1 // Selection Sort: positive elements, extra array


2

3 #include <stdio.h>
4 #define SIZE 1000
5

6 int main(){
7 int a[SIZE], b[SIZE], n, i, j, max;
8

9 printf("Enter n: ");
10 scanf("%d", &n);
11 printf("Enter the elements (all positive): ");
12

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


14 scanf("%d", &a[i]);
15

16 // max = index of the largest element in a[]


17

18 for(i=max=0; i<n; i++){


19 for(j=0; j<n; j++){
20 if(a[j] > a[max]) // the 1st trick!
21 max = j;
22 }
23 b[n-1-i] = a[max];
24 a[max] = 0; // the 2nd trick!
25 }
26

27 printf("Elements in b[] after sorting a[]: ");


28 for(i=0; i<n; i++)
29 printf("%d ", b[i]);
30 printf("\n");
31

32 return 0;
33 }
5. rArray unions Given two arrays A and B containing m and n integer elements respectively, find the

©Partha Bhowmick
48 Chapter 5. One-dimensional arrays

elements in A Y B, store them in another array C, and print C. Assume that all elements of A are
distinct, and so also for B, although an element of A may be present in B.

1 // Array union
2

3 #include <stdio.h>
4 #define SIZE 1000
5

6 int main(){
7 int a[SIZE], b[SIZE], c[2*SIZE], m, n, i, j, k, flag;
8

9 printf("Enter m: ");
10 scanf("%d", &m);
11 printf("Enter the elements of a[]: ");
12 for(i=0; i<m; i++)
13 scanf("%d", &a[i]);
14

15 printf("Enter n: ");
16 scanf("%d", &n);
17 printf("Enter the elements of b[]: ");
18 for(i=0; i<n; i++)
19 scanf("%d", &b[i]);
20

21 // copy a[] to c[]


22 for(i=k=0; i<m; i++, k++)
23 c[k] = a[i];
24

25 // Now copy each element of b[] to c[] if it’s not in a[]


26 for(i=0; i<n; i++){
27 flag = 0; // assume that b[i] is not in a[]
28 for(j=0; j<m; j++){
29 if(b[i]==a[j]){ // b[i] is in a[]
30 flag = 1;
31 break;
32 }
33 }
34 if(!flag) // b[i] is not in a[], so copy it to c[]
35 c[k++] = b[i];
36 }
37

38 printf("c[] = ");
39 for(i=0; i<k; i++)
40 printf("%d ", c[i]);
41 printf("\n");
42

43 return 0;
44 }
6. rClosest pair in 2Ds Given an integer n ě 2, followed by a sequence of n distinct points with real
coordinates, determine a pair of closest points. You can store the x-coordinates and the y-coordinates
in two arrays.

1 #include<stdio.h>
2 #include <float.h>

©Partha Bhowmick
Chapter 5. One-dimensional arrays 49

4 int main(){
5 float x[100], y[100]; // assuming that there are at most 100 points
6 int n, i, j, p, q;
7 float dcur, dmin; // we consider the squares of distances; need not use math library
8 dmin = FLT_MAX; // the maximum value of a float
9

10 printf("Enter #points: ");


11 scanf("%d", &n);
12 printf("Enter the coordinates:\n");
13 for(i=0; i<n; i++){
14 printf("%2d: ", i+1);
15 scanf("%f%f", &x[i], &y[i]);
16 }
17

18 for(i=1; i<n; i++){


19 for(j=0; j<i; j++){
20 dcur = (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]);
21 if (dcur < dmin)
22 p = i+1, q = j+1, dmin = dcur;
23 }
24 }
25

26 printf("Closest pair = (%d, %d), distance = %0.3f.\n", p, q, dmin);


27 return 0;
28 }

5.7 Exercise problems

Note the following regarding the problems stated in this section.


i. All arrays here are one-dimensional. The number of elements that an array can store, is referred to as
the size of array. However, the full array may not be used. For example, the size of an array Ar s may
be 10, but we store and work with only 7 elements from Ar0s to Ar6s, whereby Ar7s to Ar9s are of no
use.
ii. Unless mentioned, for an array, assume that its size is at most 1000.
iii. Unless mentioned, assume that the input elements need not be distinct.
1. (Check if sorted) Given a positive integer n as the first input, take in as the next input n integer
elements from the user, store them in an array, and check if they are sorted in non-decreasing order.
The total number of comparisons should be at most n ´ 1.
2. (Largest-sum pair) Given a positive integer n as the first input, take in as the next input n integer
elements from the user, store them in an array, and find a pair of elements that add up to the largest
value over all pairs. For example, for r´2, 5, ´1, 3, ´1, 2, 3s, the largest sum is 5 ` 3 “ 8. (Hint: It’s the
pair of max and 2nd max.)
3. (Pair sum) Given a positive integer n and an integer k, followed by n integer elements, store them in
an array and determine whether there are two elements with distinct indices in the array such that their
sum is k.
4. (Binomial coefficients) From the following recurrence of binomial coefficients
ˆ ˙ ˆ ˙ ˆ ˙
n n! n´1 n´1
“ “ ` , (5.2)
k k!pn ´ kq! k´1 k

©Partha Bhowmick
50 Chapter 5. One-dimensional arrays

compute the values of for k “ 0, 1, . . . , n, using the value of n as input. You should do it with a
` n˘
k
single array.
5. (Selection Sort: positive and distinct elements, extra array) Given a positive integer n as the
first input, take in as the next input n positive integers from the user and store them in an array A.
Take another array B of the same size and put the elements of A into B so that they are in increasing
order and all the elements of B are distinct. For example, if A “ r4, 2, 3, 2, 6, 4s, then B “ r2, 3, 4, 6s.
Since the size of B is same as that of A, you have to keep track of the number of elements in B.
6. (Selection Sort) Given a positive integer n as the first input, take in as the next input n integers
from the user and store them in an array A. Without using any extra array, rearrange the elements
in non-decreasing order. For example, if input is A “ r4, ´2, 3, 0, ´2, 6, 4s, then the output will be
A “ r´2, ´2, 0, 3, 4, 4, 6s.
7. (Array intersection) Given two arrays A and B containing m and n integer elements respectively,
find the elements in A X B, store them in another array C, and print C. Assume that all elements of A
are distinct, and so also for B.
8. (Maximum collinearity) Given an integer n ě 2, followed by a sequence of n distinct points with
integer coordinates, determine the maximum number of collinear points. You can store the x-coordinates
and the y-coordinates in two arrays.

©Partha Bhowmick
6 | Functions

6.1 What is function?


A function is a block
` ˘of code meant to perform a computational task, e.g., to compute a mathematical
function such as n!, nr , GCDpa, bq, xy , sin x, and so on. Apart from mathematical functions, there are many
computational problems where functions are required to write efficient codes—for example, to enumerate all
primes less than a given natural number (solved in §6.14).
Every C program must contain a function named main(). In addition, it may contain other functions.
Execution of the program always begins by carrying out the instructions in main().
Any function other than main() runs only when it is called by a function such as main() or some other
function, including itself. If it calls itself, it is said to be recursive (see §6.4).
Functions are of two categories: i) library functions and ii) user-defined functions. There are many
libraries in C such as stdio.h, stdlib.h, math.h, string.h, etc. Each such library is basically a collection
of predefined functions. For example, scanf, printf, getc, and putc are some functions defined in stdio.h.
The functions abs, atoi, calloc, and malloc are some commonly used functions defined in stdlib.h. In
the math library math.h, we have many predefined mathematical functions such as sqrt, pow, sin, cos,
asin, abs, etc. While processing strings, we need to include the library string.h to use functions like
strlen, strcmp, etc.1
A user-defined function is written by the programmer. It needs to be` written when it is not predefined
in any standard library. One such example is to compute the value of nr for two integers n and r with
˘

0 ď r ď n. You can see its code in §6.14.

6.2 Why function?


A function may take some input arguments or parameters and may return some value. It may be called
multiple times, with same or different arguments. Thus, functions are particularly useful when they need to
be called repeatedly. It makes a smart programming—write once, call again and again. They come handy
while developing a software in a modular fashion. Large codes become easy to read and easy to debug or
revise.

6.3 Defining a function

A function definition has two parts: header and body (Figure 6.1). The header carries the function prototype
or declaration, which consists of:
1. return data type, i.e., data type of the variable whose value is returned by the function;
1A detailed list of C library functions can be seen at https://en.wikipedia.org/wiki/C_standard_library

51
52 Chapter 6. Functions

argument types
function name argument names

return
data type float dis(int a, int b){ header = protoype or delclaration

float x = a*a+b*b;
body = definition
return statement return sqrt((float)x);
}

Figure 6.1: Components of a user-defined function named dis. Notice that dis calls another function, sqrt,
which is defined in the math library.

function name
no argument

return
int main(){ header = protoype or delclaration
data type
int a, b;
printf("Enter a, b: ");
scanf("%d%d", &a, &b); body = definition

printf("a/b = %0.3f", dis(a,b)); function call (1st)

printf("a/b = %0.3f", dis(a+1,b)); function call (2nd)

return statement return 1;


}

Figure 6.2: Calling the function dis from main(). Here, dis is the called function, and main() the caller.

2. name of the function;


3. names and data types of the variables taken as input arguments or parameters.
When no value needs to be returned, the return data type is void. When no input argument is required,
there is nothing between the opening and the closing brackets. One such common example is the function
int main(), shown in Figure 6.2. Notice here that main() calls the user-defined function dis with two
integer variables as arguments. In the first call, the arguments are a and b, while in the second, they are
a+1 and b.
The header of a function is analogous to the domain of definition of a mathematical function; e.g., in
n!, the domain is the set of positive integers. The body, on the other hand, contains the definition of the
function and its returned value, if any; e.g., for n!, the definition is 1 ¨ 2 ¨ 3 ¨ ¨ ¨ n and its value is an integer.
Typically, a function is defined before it is called. The main() function is usually the last function in
a program, making it easier for the compiler to identify function definitions in a single pass through the
file. However, when there are many functions that call each other arbitrarily, it can be more convenient to
place the function definitions after main(). In such cases, to inform the compiler about a function before
it is called, all function prototypes are declared before main(), with their complete definitions (including
prototypes and bodies) written afterward.
For example, consider the problem of computing the number of permutations of r elements chosen from
n distinct elements, given by the formula P pn, rq “ pn´rq!
n!
. Below are two versions of a program to compute
and print the values of P pn, rq for r P r1, ns, where n is provided by the user.
In the first version, the function prototypes are declared separately before main(), and their definitions
are placed later. In the second version, the prototypes are omitted, requiring the function definitions to
appear before main(). Additionally, in the second version, the fact function is defined before the npr

©Partha Bhowmick
Chapter 6. Functions 53

function because the latter calls the former. If fact were placed after npr, a compilation error would occur,
as a called function must be defined before its caller if no prototypes are declared separately.

1 // P(n,r): Version 1 (prototypes are declared separately)


2

3 #include <stdio.h>
4

5 int npr (int n, int r); // prototype of the function npr


6 int fact (int n); // prototype of the function fact
7

8 int main(){
9 int i, n;
10 printf("Enter n: ");
11 scanf ("%d", &n);
12 for (i=1; i<=n; i+=1)
13 printf ("%d choose %d = %d \n", i, n, npr(n, i));
14 }
15

16 int npr(int n, int r){ // definition of the function npr


17 return fact(n)/fact(n-r);
18 }
19

20 int fact(int n){ // definition of the function fact


21 int i, f=1;
22 for (i=1; i<=n; i++)
23 f *= i;
24 return f;
25 }

1 // P(n,r): Version 2 (prototypes are not declared separately)


2

3 #include <stdio.h>
4

5 int fact(int n){ // definition of the function fact


6 int i, f=1;
7 for (i=1; i<=n; i++)
8 f *= i;
9 return f;
10 }
11

12 int npr(int n, int r){ // definition of the function npr


13 return fact(n)/fact(n-r);
14 }
15

16 int main(){
17 int i, n;
18 printf("Enter n: ");
19 scanf ("%d", &n);
20 for (i=1; i<=n; i+=1)
21 printf ("%d choose %d = %d \n", i, n, npr(n, i));
22 }

©Partha Bhowmick
54 Chapter 6. Functions

6.4 Recursive function


A recursive function is one that calls itself. It is easy to write for a mathematical recurrence. Take, for
example, computing the value of n!, where n is a positive integer. It can be recursively written as

if n “ 1
"
1
n! “
n ¨ pn ´ 1q! otherwise.

Its recursive program is straightforward and would be as follows.

int fact(int n){


if (n==1) // base condition
return 1;
else
return n * fact(n-1); // recursion
}

We could make an equivalent code with the recursion written before the base condition, which would look
as follows.

int fact(int n){


if (n>1) // recursion
return n * fact(n-1); // base condition
else
return 1;
}

Although both are correct, the latter is a bad coding style because the memory requirement of the recursion
stack will be more compared to the former. So, unless there is any compelling reason, base condition should
be written before recursion while writing a recursive function.

6.5 The return statement


A function with return type other than void always returns a value, and it is always a single value. The
value can be of any expression matching the return type. If the return type is void, then return is optional.
The body of a function may contain more than one return. As a result, the statement return may
terminate the execution of a function before it reaches the end of its body. The following code, for example,
uses the statement return thrice, with the objective of finding the largest among three integers.

int max(int a, int b, int c){


if (a >= b && a >== c)
return a;
if (b >= a && b >== c)
return b;
return c;
}

In a value-returning function, return does two distinct things:


i) specifies the value to be returned, once that value is obtained;
ii) terminates the execution of the called function and transfers the program control back to the caller
function.

©Partha Bhowmick
Chapter 6. Functions 55

6.6 Local and global variables

The variables declared inside a function are said to be its local variables. Called so because there is a
concept of global variables on the contrary, which are declared outside all functions, i.e., just after all
#include statements and before the main(). The local variables can be accessed only within the function
in which they are declared. Local variables cease to exist when the function terminates. Each execution of
the function uses a new set of local variables, and input arguments or parameters are also local in the same
sense.
For example, in Figure 6.1, x is a local variable of dis, whereas a and b are its two input parameters.
Know that the input parameters a and b of dis are physically different from the local variables a and b in
main() (Figure 6.2). Yes, although their names in dis are same with those in main(), they are physically
different! This is because they have different addresses in the memory. It is analogous to our very common
experience that two persons from two different families may have the same name!

6.7 Scope of a variable

The scope of a variable means the part of the program that can use the value of the variable. It is basically
the block in which it is defined. Recall that a block means the sequence of statements enclosed within two
matching curly brackets.
For a local variable, the scope the entire function in which it is defined, provided it is declared in the
very beginning of the body of the function. Two local variables of two functions can have the same name, but
they are actually different variables because the variable name works as its first name whereas its surname
is the function name.
Any global variable, since being declared outside all functions including main(), has its scope all over
the program by default. However, it scope will be hidden in a block if a local variable of the same name is
defined in that block. Use of global variables, unless there is a compelling reason, should be avoided.
Here is an example showing how a global variable A is declared and used by two different functions,
namely main() and myProc(). The value of A is printed twice: first from myProc() and then from main().
Since myProc() changes the value of A to 2 and main() reads that value later, in both cases, the printed
value will be 2.

1 #include <stdio.h>
2 int A; // This A is a global variable
3 void main(){
4 A = 1;
5 myProc();
6 printf("A = %d\n", A);
7 }
8

9 void myProc(){
10 A = 2;
11 printf("A = %d\n", A);
12 }

In the following code, note that the declaration int A = 2; in myProc() creates an integer variable
with the same name, A. This A is local to myProc(), and when it is printed, the output is 2. This does not
affect the value of the global variable A. Consequently, when A is printed from main(), the output is 1, which
is the value of the global variable A.

©Partha Bhowmick
56 Chapter 6. Functions

1 #include <stdio.h>
2 int A; // This A is a global variable
3 void main(){
4 A = 1;
5 myProc();
6 printf("A = %d\n", A);
7 }
8

9 void myProc(){
10 A = 2;
11 printf("A = %d\n", A);
12 }

This practice of declaring local and global variables with the same name should be avoided when writing
code.

6.8 Parameter passing


Parameter or argument passing is required while invoking functions, i.e., when a function calls another
function or calls itself, the former being referred to as the calling or caller function, whereas the latter as
called function. The parameter passing is done to the called function from the caller function. For example,
in Figure 6.2, the values of the parameters a and b are passed to dis from main().

6.8.1 Passing by value


It is also referred to as call by value. The called function gets a ‘copy’ of the value of each parameter, as it
is passed to it by the caller function. In simpler words, the copy is treated as the value of a new variable
associated with the called function only. Thus, execution of the called function has no effect on the values of
the parameters of the caller. The copy does not exist when the called function ends and the program control
returns to the caller function. A parameter passed from the caller may also be an expression, e.g., n-r is the
argument passed from main() when it invokes fact(n-r).

6.8.2 Passing by reference


It is also termed as call by reference. It is not directly supported in C, but supported in some other languages
like C++. In C, we can instead pass copies of addresses to get the desired effect, as follows. The caller passes
a copy of the address of a variable to the called function. Since the address is passed, execution of the called
function may affect the value of the parameter in the caller function. A very common example is the function
swap that exchanges the values of two variables declared and defined in main(). We shall see this later when
working with pointers.

6.9 Passing an array to a function


While passing an array to a function, the name of the array is used as an argument. Now, beware of the
catch here—since the name of the array is the argument, the values of the array elements are not passed to
the called function. Rather, the array name is interpreted as the address of the first element of the array,
and so what is passed is basically the first element’s address. In this regard, the way it is passed differs from
that for ordinary variables.
Repeating again, the argument carries the address of the first element of the array. When any element
of that array has to be accessed inside the called function, its address is calculated by the compiler using

©Partha Bhowmick
Chapter 6. Functions 57

the technique discussed in §5.2. Clearly, this address is address is same to both the caller and the called for
any element of the array, and it is also accessible to both of them. Hence, any change made to any element
inside the called function is eventually reflected in the calling function, once the called function ends. In the
following code, for example, the elements of a 5-element array are squared in the called function, and when
printed from the caller, the squared elements will be printed as desired.

void doSqr(int a[], int n){


for(int i=0; i<n; i++)
a[i] *= a[i];
}

int main(){
int a[] = {3, -2, 1, 2, 1};
doSqr(A, 5);
for(int i=0; i<5; i++)
printf("%d ", a[i]); // will print 9 4 1 4 1
return 1;
}

6.10 More on recursion


As mentioned in §6.4, a recursive function calls itself repeatedly. It may call itself either directly or indirectly
in a cyclic chain. Following are two typical examples defined for all positive integers n; here, f pnq is a direct
recursion but gpnq is not; the function g doesn’t call itself directly but calls h, which calls back g in turn.
For h also, it’s an indirect recursion.

if n “ 1
"
1
Direct recursion: f pnq “
n ¨ f pn ´ 1q otherwise.
if n “ 1
"
1
Indirect recursion: gpnq “
n ¨ hpn ´ 1q otherwise.
if n “ 1
"
1
Indirect recursion: hpnq “
1 ` gpn ´ 1q otherwise.

An important property of recursion is that when the recursive function is called next time, it acts on
a smaller input, and so eventually the recursion reaches a/the base case. For example, in Figure 6.3, the
base case is for 1, and from that point the recursion wraps up, to get the values of fact(2), fact(3),
and fact(4), in that order. This ‘wrapping up’ is referred to as backtracking. Notice that the C function
fact(n) is basically the mathematical function f pnq mentioned above.
As evident from Figure 6.3, upon reaching the base case, that recursive call ends, and the program
control backtracks to the previous call. The previous recursive call may have some pending instructions, and
those pending instructions are all stored in the memory in a generic data structure called stack, which in
this context is particularly referred to as recursion stack. In the example of fact(4), the stack contains all
the pending instructions of fact(4), fact(3), and of fact(2) when it reaches fact(1). While a recursion
unfolds, the stack grows up, and when backtracking starts, it shrinks down (Figure 6.4).
The stack maintains all the records (i.e., pending instructions and associated data) of all the unfinished
recursive calls in an orderly manner. The last record is of the last recursive call, and while backtracking,
it is the last record which is first processed. For example, the record of fact(2) is first processed while
backtracking after reaching the base condition (Figure 6.4). These records are called activation records and
need to be stored in LIFO order (Last In, First Out), and so the data structure is stack. An activation
record of a function call contains several parts including its return address, arguments, and local variables.

©Partha Bhowmick
58 Chapter 6. Functions

fact(4) 4*6 = 24

1st recursion
if(4==1) return 1;
else return 4*fact(3); 3*2 = 6

2nd recursion
if(3==1) return 1;
else return 3*fact(2); 2*1 = 2

3rd recursion
if(2==1) return 1;
else return 2*fact(1); 1

Base case
if(1==1) return 1;
else return 1*fact(0);

Figure 6.3: Recursive steps after calling the function fact(4) from main().

base condition reached


Unfolding of recursion Backtracking
3rd recursion 1
fact(1)
2nd recursion 2
fact(2) fact(2) fact(2)
1st recursion 6
function call fact(3) fact(3) fact(3) fact(3) fact(3)
fact(4) 24
fact(4) fact(4) fact(4) fact(4) fact(4) fact(4) fact(4)
main() main() main() main() main() main() main() main() main()
Time

Figure 6.4: Recursion stack corresponding to fact(4) called from main().

6.11 Macros (#define)


Macros are a powerful feature in C language that allows you to define constants or expressions that can
be reused throughout the program. A macro serves as a placeholder for the specified value or expression.
It is created by the #define directive. During preprocessing, which occurs before the compilation stage,
the preprocessor scans through the code and substitutes every occurrence of the macro with the value or
expression it represents.
For example, consider the macro definition: #define PI 3.14159. Whenever the macro PI is used in
the code, the preprocessor will automatically replace it with 3.14159. This substitution happens at every
instance where PI appears, excepting the format string in printf. This is done by the programmer to ensure
consistency and to reduce the risk of errors associated with manual input of constant values.
Let’s illustrate the use of a macro with an example where we compute the perimeter and the area of a
circle, given by 2πr and πr2 , respectively, where r is the radius of the circle. Here is how you can define and
use a macro for π:

#include <stdio.h>
#define PI 3.14159

int main() {
float radius, perimeter, area;

©Partha Bhowmick
Chapter 6. Functions 59

printf("Enter the radius of the circle: ");


scanf("%f", &radius);
perimeter = 2.0 * PI * radius;
area = PI * radius * radius;
printf("Perimeter = %0.3f, area = %0.3f\n", perimeter, area);
return 0;
}

The #define directive in C not only allows you to define simple constants but also enables the creation
of macros with arguments, which are similar to functions. These macros can take one or more arguments,
and during preprocessing, the arguments are replaced with the values passed when the macro is invoked.
This capability allows you to create flexible and reusable code snippets.

6.12 #define with arguments


A macro with arguments is defined using the same #define directive but includes a list of parameters in
parentheses after the macro name. When the macro is used in the code, the preprocessor replaces the macro
call with the macro definition, substituting the arguments with the corresponding values passed in the call.
For example, this is a macro that calculates the square of a number:

#define SQR(x) ((x)*(x))

In this example, the macro sqr takes one argument, x. When you use sqr in your code, the preprocessor
replaces it with the expression ((x)*(x)). Here is how you can use it:

#define SQR(x) ((x)*(x))


int main() {
int n = 5;
printf("The square of %d is %d\n", n, SQR(n));
return 0;
}

When the preprocessor processes this code, the line:

printf("The square of %d is %d\n", n, SQR(n));

is replaced with:

printf("The square of %d is %d\n", n, ((x)*(x)));

This substitution ensures that the macro works correctly, even if the argument n is an expression rather than
a simple variable. For example, if you write SQR(a+b), the macro expands to ((a+b)*(a + b)), ensuring
that the entire expression is squared.
You have to be careful while defining a macro. For example, if you write #define SQR(x) x*x, then
SQR(a+b) will result in a+b*a+b, which is incorrect.
As you understand now, macros with arguments have definite advantages in coding. First, they simplify
complex expressions by encapsulating them in a single, easy-to-use macro. Second, they are efficient because
they are expanded inline, avoiding the overhead of function calls. Third, they allow you to create reusable
code snippets that can be adapted to different inputs. Some typical use case for macros are given in Table 6.1.
Following is a program where the macro SWAP(a, b, type) is used.

©Partha Bhowmick
60 Chapter 6. Functions

Table 6.1: Some typical examples of macros.

#define SQR(x) ((x) * (x)) // Square of a number x


#define CUBE(x) ((x) * (x) * (x)) // Cube of a number x
#define AVG(a, b) ((a) + (b)) / 2.0 // Average of two numbers a and b
#define ABS(x) (((x) < 0) ? -(x) : (x)) // Absolute value of a number x
#define IS_EVEN(x) (((x) % 2) == 0) // Check if a number x is even
#define IS_ODD(x) (((x) % 2) != 0) // Check if a number x is odd
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) // Minimum of two numbers a and b

// Check if a number x is within a range [low, high]


#define IN_RANGE(x, low, high) (((x) >= (low)) && ((x) <= (high)))

// Determine the maximum of three numbers a, b, and c


#define MAX3(a, b, c) (((a) > (b)) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c)))

// Find the median of three numbers a, b, and c


#define MED(a, b, c) (((a)<(b))?(((b)<(c))?(b):((a)<(c))?(c):(a)):(((a)<(c))?(a):((b)<(c))?(c):(b)))

// Calculate the distance between two points (x1, y1) and (x2, y2)
#define DIS(x1, y1, x2, y2) sqrt(((x2)-(x1)) * ((x2)-(x1)) + ((y2)-(y1)) * ((y2)-(y1)))

#define PI (2.0 * asin(1)) // Define the best-possible value of pi using math.h


#define DEG_TO_RAD(x) ((x) * (PI) / 180.0) // Convert an angle x from degrees to radians
#define RAD_TO_DEG(x) ((x) * 180.0 / (PI)) // Convert an angle x from radians to degrees
#define CIRP(r) (2 * PI * (r)) // Calculate the perimeter of a circle with radius r
#define CIRA(r) (PI * (r) * (r)) // Calculate the area of a circle with radius r

// Swap two variables a and b


#define SWAP(a, b, type) { type temp = (a); (a) = (b); (b) = temp; }

1 #include <stdio.h>
2

3 // Macro to swap two variables of a given type


4 #define SWAP(a, b, type) { type temp = (a); (a) = (b); (b) = temp; }
5

6 int main() {
7 // Declare and initialize variables
8 int x = 10, y = 20;
9 double p = 3.14, q = 2.71;
10 char c1 = ’A’, c2 = ’B’;
11

12 // Swap integers
13 printf("Before swapping: x = %d, y = %d\n", x, y);
14 SWAP(x, y, int);
15 printf("After swapping: x = %d, y = %d\n\n", x, y);
16

17 // Swap doubles
18 printf("Before swapping: p = %.2f, q = %.2f\n", p, q);
19 SWAP(p, q, double);
20 printf("After swapping: p = %.2f, q = %.2f\n\n", p, q);
21

22 // Swap characters
23 printf("Before swapping: c1 = %c, c2 = %c\n", c1, c2);
24 SWAP(c1, c2, char);

©Partha Bhowmick
Chapter 6. Functions 61

25 printf("After swapping: c1 = %c, c2 = %c\n", c1, c2);


26

27 return 0;
28 }

6.13 Extra topics


These topics may not be in your syllabus. Please get it confirmed from your teacher.

6.13.1 Generating random input using rand


Random input is crucial for testing and analyzing systems with large data sizes because it helps in simulating a
wide range of possible scenarios and corner cases. When dealing with substantial datasets, manually crafting
diverse test-cases becomes impractical. Randomly generated data ensures that the system is exposed to
various combinations and distributions of input, which can reveal potential issues such as performance
bottlenecks, boundary conditions, or unexpected behaviors. This approach is essential for validating the
robustness and reliability of algorithms and applications, ensuring they perform well under realistic and
unpredictable conditions.
The next C program demonstrates how to use the rand function with srand for seed generation to fill an
array of 100 integers with values in a user-defined interval [a,b]. The user inputs the interval bounds a and
b. The srand function is used to seed the pseudo-random number generator with the current time, ensuring
different random sequences on each execution. The rand function generates random numbers, which are
then scaled to fall within the interval [a,b]. The program finally prints the filled array.
The macro #define RANDOM_IN_RANGE(a, b) generates a random integer in [a,b], by using the rand()
function and adjusting the range accordingly. The library stdlib.h provides access to the rand() function
for generating random numbers and srand() for setting the seed, while the library time.h is used to obtain
the current time with time(NULL), which initializes the seed for rand() to ensure that the sequence of random
numbers varies with each execution. This combination is essential for producing diverse and unpredictable
random values.

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h>
4

5 #define SIZE 100


6

7 // Macro to generate a random integer between a and b


8 #define RANDOM_IN_RANGE(a, b) ((a) + rand() % ((b) - (a) + 1))
9

10 int main() {
11 int a, b;
12 int array[SIZE];
13

14 // Get the interval bounds from the user


15 printf("Enter the lower bound (a): ");
16 scanf("%d", &a);
17 printf("Enter the upper bound (b): ");
18 scanf("%d", &b);
19

20 // Seed the random number generator with the current time


21 srand(time(NULL));

©Partha Bhowmick
62 Chapter 6. Functions

22

23 // Fill the array with random integers in the interval [a, b]


24 for (int i = 0; i < SIZE; i++) {
25 array[i] = RANDOM_IN_RANGE(a, b);
26 }
27

28 // Print the filled array


29 printf("Array filled with random integers between %d and %d:\n", a, b);
30 for (int i = 0; i < SIZE; i++) {
31 printf("%d ", array[i]);
32 }
33 printf("\n");
34

35 return 0;
36 }

Below is a modified version of the above code in which the seed is an integer r taken in from the user,
rather than using a time-dependent seed. Note that the number of elements is also taken from the user.

1 #include <stdio.h>
2 #include <stdlib.h>
3

4 #define RANDOM_IN_RANGE(a, b) ((a) + rand() % ((b) - (a) + 1))


5

6 int main() {
7 int a, b, r, n;
8

9 // Prompt user for the range [a, b], the seed value, and the number of elements
10 printf("Enter the lower bound (a): ");
11 scanf("%d", &a);
12 printf("Enter the upper bound (b): ");
13 scanf("%d", &b);
14 printf("Enter the seed value (r): ");
15 scanf("%d", &r);
16 printf("Enter the number of elements (n): ");
17 scanf("%d", &n);
18

19 // Initialize the random number generator with the user-provided seed


20 srand(r);
21

22 // Fixed-size array
23 int arr[100];
24

25 // Ensure n does not exceed the array size


26 if (n > 100) {
27 printf("The number of elements cannot exceed 100.\n");
28 return 1;
29 }
30

31 // Fill the array with random integers in the range [a, b]


32 for (int i = 0; i < n; i++) {
33 arr[i] = RANDOM_IN_RANGE(a, b);
34 }
35

©Partha Bhowmick
Chapter 6. Functions 63

36 // Display the generated array


37 printf("Generated array:\n");
38 for (int i = 0; i < n; i++) {
39 printf("%d ", arr[i]);
40 }
41 printf("\n");
42

43 return 0;
44 }

Here are the outputs for two different seeds provided by the user, while the interval [a,b] remains
unchanged. Notice how the outputs differ due to the variation in seeds.

Enter the lower bound (a): 10


Enter the upper bound (b): 13
Enter the seed value (r): 1
Enter the number of elements (n): 5
Generated array:
13 12 11 13 11

Enter the lower bound (a): 10


Enter the upper bound (b): 13
Enter the seed value (r): 2
Enter the number of elements (n): 5
Generated array:
12 13 10 13 11

6.13.2 main() with arguments


The main() function serves as the entry point of a C program, where the execution begins. When main()
is defined without arguments, it takes the form int main(void) or simply int main(). In this case, the
function does not accept any input from the command line, and the program runs independently of any
external input.
Alternatively, main() can be defined with arguments, typically as int main(int argc, char *argv[].
Here, argc (argument count) represents the number of command-line arguments passed to the program, and
argv (argument vector) is an array of strings holding the actual arguments. This form of main() is crucial
when a program needs to process input provided by the user at runtime, such as file names, options, or other
data.
To run a program with arguments, you execute the compiled program in the command line followed by
the desired arguments. For instance, if your executable is named a.out, and you want to pass two arguments
input.txt and output.txt, you would run the command:

./a.out input.txt output.txt

This allows the program to dynamically adjust its behavior based on the provided inputs, making it more
versatile and interactive.
Here is a C program that takes numbers as command-line arguments and prints their square roots to
the terminal:

1 #include <stdio.h>
2 #include <stdlib.h> // Include stdlib.h for atof()
3 #include <math.h> // Include math.h for sqrt()

©Partha Bhowmick
64 Chapter 6. Functions

5 int main(int argc, char *argv[]) {


6 // Check if at least one number is provided as argument
7 if (argc < 2) {
8 printf("Usage: %s <number1> <number2> ... <numberN>\n", argv[0]);
9 return 1;
10 }
11

12 // Loop through each argument provided


13 for (int i = 1; i < argc; i++) {
14 // Convert the argument from string to double
15 double num = atof(argv[i]);
16

17 // Calculate the square root


18 double squareRoot = sqrt(num);
19

20 // Print the result to the terminal


21 printf("Square root of %.2lf is %.4lf\n", num, squareRoot);
22 }
23

24 return 0;
25 }

Here is a snapshot of its compilation and execution:

gcc mainWithArgs_SqRootsTerminal.c -lm


./a.out 4 6 7 9
Square root of 4.00 is 2.0000
Square root of 6.00 is 2.4495
Square root of 7.00 is 2.6458
Square root of 9.00 is 3.0000

Here is another C program where the input file contains some numbers, and the output file will store
their square roots:

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4

5 int main(int argc, char *argv[]) {


6 FILE *inputFile, *outputFile;
7 double num;
8

9 // Open input file in read mode


10 inputFile = fopen("input.txt", "r");
11 if (inputFile == NULL) {
12 printf("Error opening input file.\n");
13 return 1;
14 }
15

16 // Open output file in write mode


17 outputFile = fopen("output.txt", "w");
18 if (outputFile == NULL) {
19 printf("Error opening output file.\n");
20 fclose(inputFile);

©Partha Bhowmick
Chapter 6. Functions 65

21 return 1;
22 }
23

24 // Read each number, calculate its square root, and write to the output file
25 while (fscanf(inputFile, "%lf", &num) != EOF) {
26 fprintf(outputFile, "Square root of %.2lf is %.4lf\n", num, sqrt(num));
27 }
28

29 // Close the files


30 fclose(inputFile);
31 fclose(outputFile);
32

33 return 0;
34 }

6.14 Solved problems


You should not use any library other than stdio.h, unless mentioned otherwise.
1. rPrinting primes up to a given numbers Write a function of the prototype int checkPrime(int x).
It takes as input an integer x, checks whether it’s prime, and returns 1 if so, and 0 otherwise. Scan a
positive integer n from main() and print all primes in r1, ns by calling the above function in a loop.

1 #include <stdio.h>
2 #include <math.h>
3

4 int checkPrime(int x){


5 int isPrime = 1;
6 for(int i = 2; (i <= sqrt(x)) && isPrime; i++){
7 if(x%i==0)
8 isPrime = 0;
9 i++;
10 }
11 return isPrime;
12 }
13

int main(){
14

15 int n;
16 printf("Enter a positive integer: ");
17 scanf("%d", &n);
18 for(int j=3; j<=n; j++)
19 if(checkPrime(j))
20 printf("%d is prime\n", j);
21 return 0;
22 }
2. n choose r: nr Write two functions of the following prototypes:
“ ` ˘‰

int ncr (int n, int r);


int fact (int n);
The first function will compute the value of nr “ r!pn´rq! , and to do so, it will call the second one to
` ˘ n!

get the values of n!, r!, and pn ´ rq!. Scan a positive integer n from main() and print the values of nr
` ˘

for r P r0, ns, by calling the function ncr in a loop. For example, for n “ 5, it will print 1, 5, 10, 10, 5, 1.

©Partha Bhowmick
66 Chapter 6. Functions

1 #include <stdio.h>
2

3 int ncr (int n, int r); // prototype of the function ncr


4 int fact (int n); // prototype of the function fact
5

6 int main(){
7 int i, n;
8 printf("Enter n: ");
9 scanf ("%d", &n);
10 for (i=0; i<=n; i+=1)
11 printf ("%d choose %d = %d \n", i, n, ncr(n, i));
12 }
13

14 int ncr(int n, int r){ // definition of the function ncr


15 return fact(n)/fact(r)/fact(n-r);
16 }
17

18 int fact(int n){ // definition of the function fact


19 int i, f=1;
20 for (i=1; i<=n; i++)
21 f *= i;
22 return f;
23 }
3. rValue of a quadratic functions Write a function to compute the value of ax2 ` bx ` c with a, b, c, x
as real values and taken as arguments in that order. Scan their respective values from main(), call that
function from main(), and print its returned value from main().

1 // Value of a quadratic function


2

3 #include <stdio.h>
4

5 float f(float a, float b, float c, float x){


6 return a*x*x + b*x + c;
7 }
8

9 int main(){
10 float a, b, c, x;
11 printf("\nEnter a, b, c, x: ");
12 scanf("%f%f%f%f", &a, &b, &c, &x);
13 printf("f = %f\n", f(a,b,c,x));
14 return 0;
15 }
4. rArithmetic and geometric meanss Write a function to compute and print the arithmetic mean and
the geometric mean of n real numbers, with n and an n-element array as arguments. The value of n and
the array elements will be supplied as input from main(). The math library can be used, but only for
the pow() function.

1 // Arithmetic and geometric means


2

3 #include <stdio.h>
4 #include <math.h>
5 #define SIZE 1000

©Partha Bhowmick
Chapter 6. Functions 67

7 void computeAMGM(int n, float a[]){


8 int i;
9 float sum=0, prod=1;
10

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


12 sum += a[i];
13 prod *= a[i];
14 }
15 printf("AM = %f, GM = %f.\n", sum/n, pow(prod, 1.0/(float)n));
16 }
17

18 int main(){
19 int n, i;
20 float a[SIZE];
21

22 printf("Enter n: ");
23 scanf("%d", &n);
24 printf("Enter the elements: ");
25

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


27 scanf("%f", &a[i]);
28

29 computeAMGM(n, a);
30

31 return 0;
32 }
5. rMedians Write a function to compute and return the median of n integers, with n and an n-element
array as arguments. Scanning the value of n along with the array elements, and printing the me-
dian, should all be done from main(). Assume that n is odd and all elements are distinct. Then, exactly
2 elements of the array will be smaller that the median—a fact that can be used to write the function.
n´1

1 // Find the median element in an array with odd number of elements


2

3 #include <stdio.h>
4 #define SIZE 1000
5

6 int readInput(int a[]){


7 int n, i;
8 printf("Enter n: ");
9 scanf("%d", &n);
10 printf("Enter the elements: ");
11 for(i=0; i<n; i++)
12 scanf("%d", &a[i]);
13 return n;
14 }
15

16 int findMedian(int a[], int n){


17 int i, j, k, m;
18 for(i=0; i<n; i++){
19 for(j=0, k=0; j<n; j++){
20 if(a[j]<a[i])
21 k++;
22 }

©Partha Bhowmick
68 Chapter 6. Functions

23 if (k==n/2){
24 m = a[i];
25 break;
26 }
27 }
28 return m;
29 }
30

31

32 int main(){
33 int a[SIZE], n, m;
34

35 n = readInput(a);
36 m = findMedian(a, n);
37 printf("Median = %d\n", m);
38

39 return 0;
40 }
6. rGCD function, recursives Write a recursive function of the prototype int gcd(int, int) to com-
pute the GCD of two numbers, using Eq. 4.1. Take in two positive integers m, n from main(), call
gcd(m,n) from main(), and print its returned value from main().

1 //GCD function: recursive


2

3 #include <stdio.h>
4

5 int gcd(int a, int b){


6 if(a==0) return b;
7 else return gcd(b%a, a);
8 }
9

10 int main(){
11 int m, n;
12 printf("\nEnter two positive integers: ");
13 scanf("%d%d", &m, &n);
14 printf("GCD = %d\n", gcd(m,n));
15 return 0;
16 }
17

7. rGCD function, iteratives Write an iterative version of the GCD function using Eq. 4.1, keeping the
main() same as the recursive version.

1 //GCD function
2

3 #include <stdio.h>
4

5 int gcd(int a, int b){


6 int c;
7 while(a!=0){
8 c = a;
9 a = b%a;
10 b = c;
11 }

©Partha Bhowmick
Chapter 6. Functions 69

12 return b;
13 }
14

15 int main(){
16 int m, n;
17 printf("\nEnter two positive integers: ");
18 scanf("%d%d", &m, &n);
19 printf("GCD = %d\n", gcd(m,n));
20 return 0;
21 }
22

8. rGenerate all possible permutations of an arrays Write a recursive function to generate all possi-
ble permutations of a random array. The seed, the number of elements, and the range of elements are
taken in as input from the user. The function should generate permutations by swapping each element
with the first element and then recursively permuting the remaining sub-array. This problem inherently
relies on recursion to explore all possible orderings of the array elements.

1 #include <stdio.h>
2 #include <stdlib.h>
3

4 // Macro to generate a random integer in the range [a, b]


5 #define RANDOM_IN_RANGE(a, b) ((a) + rand() % ((b) - (a) + 1))
6

7 // Recursive function to generate all permutations


8 void generatePermutations(int arr[], int start, int end) {
9 if (start == end) {
10 // Print the current permutation
11 for (int i = 0; i <= end; i++) {
12 printf("%d ", arr[i]);
13 }
14 printf("\n");
15 }
16 else {
17 for (int i = start; i <= end; i++) {
18 // Swap
19 int temp = arr[start];
20 arr[start] = arr[i];
21 arr[i] = temp;
22

23 // Recursively generate permutations for the sub-array


24 generatePermutations(arr, start + 1, end);
25

26 // Backtrack by swapping back the elements


27 temp = arr[start];
28 arr[start] = arr[i];
29 arr[i] = temp;
30 }
31 }
32 }
33

34 int main() {
35 int n, seed, a, b;
36

37 // Take user input for the seed, number of elements, and the range [a, b]

©Partha Bhowmick
70 Chapter 6. Functions

38 printf("Enter the seed: ");


39 scanf("%d", &seed);
40 printf("Enter the number of elements: ");
41 scanf("%d", &n);
42 printf("Enter the range [a, b]: ");
43 scanf("%d %d", &a, &b);
44

45 // Set the seed for random number generation


46 srand(seed);
47

48 // Generate a random array within the range [a, b]


49 int arr[n];
50 for (int i = 0; i < n; i++) {
51 arr[i] = RANDOM_IN_RANGE(a, b);
52 }
53

54 // Print the generated array


55 printf("Generated array: ");
56 for (int i = 0; i < n; i++) {
57 printf("%d ", arr[i]);
58 }
59 printf("\n\n");
60

61 // Generate and print all permutations of the array


62 printf("Permutations:\n");
63 generatePermutations(arr, 0, n - 1);
64

65 return 0;
66 }
Here is a output of the above code:
Enter the seed: 1
Enter the number of elements: 3
Enter the range [a, b]: 1 9
Generated array: 2 8 1

Permutations:
2 8 1
2 1 8
8 2 1
8 1 2
1 8 2
1 2 8

6.15 Exercise problems

1. rValues of a quadratic sequences Write a function to compute the value of x2 ` bx ` c with b and c
as positive integers and x as real, taken as arguments in that order. Scan their respective values from
main(), call that function from main() for every integer value of x ranging from ´10 to 10, and print
every returned value from main(). That is, the function will be called 21 times from main().
2. rFibonacci function, recursives Write a recursive function of the prototype int f(int) to compute
the nth Fibonacci term, f pnq, using Eq. 5.1. Take in a positive integer n from main(), call f(n) from
main(), and print its returned value from main().

©Partha Bhowmick
Chapter 6. Functions 71

3. rFibonacci function, iteratives Write an iterative version of the Fibonacci function using Eq. 5.1,
keeping the main() same as the recursive version.
4. rTwo-element sum as an element in anothers Read in two integers m and n. Assume that both
m and n are in r2, 100s. Take in m integers to an array a[] and n integers to an array b[]. Write a
function that can be called from main to check whether there are two elements in a[] that add up to a
single element in b[]. The arguments of that function should be a[], b[], m, and n.

©Partha Bhowmick

You might also like