[go: up one dir, main page]

0% found this document useful (0 votes)
3 views96 pages

C Programming With Linux I

The document is a comprehensive lecture review on C programming with Linux, authored by Dr. Gourish Goudar from East West Institute of Technology. It covers various topics including algorithms, Linux file system organization, basic commands, the compilation process, and memory representation. Additionally, it provides insights into building blocks of C language and data types.

Uploaded by

gowdasanjana189
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)
3 views96 pages

C Programming With Linux I

The document is a comprehensive lecture review on C programming with Linux, authored by Dr. Gourish Goudar from East West Institute of Technology. It covers various topics including algorithms, Linux file system organization, basic commands, the compilation process, and memory representation. Additionally, it provides insights into building blocks of C language and data types.

Uploaded by

gowdasanjana189
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/ 96

C Programming - I with Linux

Lecture Review

Dr. Gourish Goudar


Dept.of Computer Science & Engineering
East West Institute of Technology
Bengaluru - 560091.
gourishgoudar@ewit.edu.in
Homepage
September, 2025
Contents
1 Basics 4
1.1 Algorithms, Pseudocode and Flowchart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.1 Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 Pseudocode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.3 Flowcharts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2 Organization of a Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.3 Linux File System Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.1 Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3.2 Example Comparison: Absolute vs. Relative Paths . . . . . . . . . . . . . . . . . . . . 13
1.4 Basic Commands and Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.1 ls - List Directory Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.2 mkdir - Make Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.3 man - Show Manual for a Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.4 cd (change directory) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.5 Using Absolute Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.6 Using Relative Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.4.7 Practical Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.4.8 touch - Create an Empty File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.4.9 cat - Concatenate and Display File Content . . . . . . . . . . . . . . . . . . . . . . . . 16
1.4.10 Using gedit on Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.4.11 cp - Copy Files or Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.4.12 mv - Move or Rename Files or Directories . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.4.13 rm - Remove Files or Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4.14 grep - Search for a Pattern in Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4.15 Understanding the chmod Command in Linux . . . . . . . . . . . . . . . . . . . . . . . 22
1.4.16 Symbolic Notation with Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.4.17 ps - Show Running Processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.4.18 top - Display Linux Tasks (System Monitoring) . . . . . . . . . . . . . . . . . . . . . . 30
1.4.19 df - Show Disk Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.5 The Compilation Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.6 Hello World Program in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.6.1 Writing the C Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.6.2 Compiling the Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

2 Information Storage and Memory Representation 35


2.1 Number System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.2 Binary Number System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.3 Interconversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.3.1 Decimal to Binary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.3.2 Binary to Decimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.3.3 Decimal to Hexadecimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.3.4 Hexadecimal to Decimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.3.5 Binary to Hexadecimal and vice versa . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.4 Memory Measurements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.5 Unsigned Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.6 Signed Numbers: Signed magnitude, one’s complement and two’s complement. . . . . . . . . 47
2.6.1 Sign-and-Magnitude Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.6.2 One’s Complement Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.6.3 Two’s Complement Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.7 Char Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.8 Floating Point Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.8.1 Fractional Binary Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

2
2.8.2 IEEE 754 format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.9 Data Types in C: signed char, unsigned char, short, unsigned short, int, unsigned, long,
unsigned long, float, double . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

3 Building Blocks and Conditional Constructs 59


3.1 Building Blocks of C Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.2 Input and Output in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.3 Initialization Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.4 Operators in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.4.1 Assignment Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.4.2 Unary Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.4.3 Binary Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.4.4 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.4.5 Relational Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.4.6 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.4.7 Precedence and Associativity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.4.8 Size of Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.5 Type Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.6 Conditional Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.7 More Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

4 Loop Constructs and Arrays 75


4.1 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1.1 FOR Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1.2 WHILE Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.1.3 DO WHILE Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.2 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.2.1 Array Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.2.2 Bounds Checking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.2.3 Initializing a 2-Dimensional Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.2.4 Memory Map of a 2-Dimensional Array . . . . . . . . . . . . . . . . . . . . . . . . . . 84
4.3 More Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

5 Functions, Scope and Storage Class 89


5.1 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
5.1.1 Defining and Calling Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
5.1.2 Function Declaration (Prototype) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
5.1.3 Arguments in Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
5.1.4 Passing Arrays to Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.2 Scope and Lifetime: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
5.2.1 Scope of Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.2.2 Lifetime of Variables and Storage Classes . . . . . . . . . . . . . . . . . . . . . . . . . 94

3
1 Basics
1.1 Algorithms, Pseudocode and Flowchart
1.1.1 Algorithms
An algorithm is a step-by-step procedure for solving a problem or performing a task. It consists of a finite
number of clearly defined steps that produce the desired result when executed.
Advantages of Using Algorithms:
1. Clarity and Structure: Algorithms provide a well-defined structure that makes tasks easier to
understand and follow.
2. Efficiency: They help optimize resource usage such as time, memory, and processing power.
3. Problem Solving: Algorithms break down complex problems into simpler steps, making them easier
to solve.

4. Reusability: Once developed, algorithms can be reused for similar tasks or problems.
5. Automation: Algorithms enable task automation in computer systems, reducing manual work.
6. Correctness: Well-designed algorithms ensure accurate and expected results.
7. Scalability: They can handle increasing amounts of data or more complex problems as needed.

8. Standardization: They provide a consistent way to solve problems, making solutions easier to test,
debug, and maintain.
Example1:

Algorithm 1: Add Two Numbers


1: Start
2: Read the first number A
3: Read the second number B
4: Compute the sum S ← A + B
5: Print the result S
6: End

Example2:

Algorithm 2: Find Maximum of Two Numbers


1: Start
2: Read the first number A
3: Read the second number B
4: if A > B then
5: Maximum ← A
6: else
7: Maximum ← B
8: end if
9: Print the result ”Maximum is:” Maximum
10: End

4
1.1.2 Pseudocode
Pseudocode is a high-level, informal way of describing an algorithm using natural language constructs and
programming-like statements. It is not meant to be executed by a computer but serves as an intermediary
between human understanding and actual code. Pseudocode is often used to plan algorithms before they
are implemented in a specific programming language.

Pseudocode Examples
Example 1: Adding Two Numbers
BEGIN
INPUT A
INPUT B
SUM = A + B
OUTPUT SUM
END

In this pseudocode:
• BEGIN and END denote the start and end of the algorithm.
• INPUT is used to read values from the user.

• SUM = A + B represents the addition of the two numbers.


• OUTPUT prints the result.

Example 2: Find the Maximum of Two Numbers


BEGIN
INPUT A
INPUT B
IF A > B THEN
MAX = A
ELSE
MAX = B
END IF
OUTPUT MAX
END

This pseudocode shows how to find the maximum of two numbers:


• It uses a conditional structure (IF-THEN-ELSE) to compare the two numbers.

• The largest number is stored in MAX and then output.

Advantages of Pseudocode
1. Simple and Easy to Understand: Pseudocode is written in plain language, making it accessible to
people with different programming backgrounds.
2. Language-Agnostic: It does not depend on any specific programming language syntax, allowing
developers to focus on the logic of the algorithm.
3. Helps in Planning: Pseudocode helps programmers plan the structure of their code before imple-
mentation. It allows them to think through the steps logically.

5
4. Improves Communication: It provides a way to communicate algorithms between team members,
even if they are using different programming languages.
5. Debugging and Refining Logic: Since pseudocode is abstract, it allows for easy identification of
logical errors without worrying about syntax errors.

6. Flexible and Modifiable: Changes to the algorithm are easier to make in pseudocode, as it doesn’t
involve complicated syntax or code structure.

1.1.3 Flowcharts
A flowchart is a diagrammatic representation of an algorithm or process. It uses various types of boxes,
connected by arrows, to represent the flow of data and control through the steps. Flowcharts are widely
used in designing and documenting processes, as they help visualize the flow of information and logic in a
clear and structured way.

Start/End
1. Oval (Start/End) Explanation: The oval symbol represents the beginning or
end of a flowchart. It is used to denote the starting and ending points of a process.

Input/Output
2. Parallelogram (Input/Output) Explanation: This symbol is used
to represent input or output operations. For example, reading data from the user or displaying results.

Process
3. Rectangle (Process) Explanation: The rectangle is used to represent a process
or operation, such as performing a calculation or executing a command.

Decision
4. Diamond (Decision) Explanation: The diamond symbol is used for decision-
making steps, where the flow can diverge based on a condition. It is usually followed by two branches
(e.g., yes or no).
5. Arrow (Flowline) Explanation: The arrow represents the flow of control from one step to the
next in a flowchart. It shows the direction in which the process is proceeding.

Connector

6. Circle (Connector) Explanation: The circle is used as a connector in cases where a


flowchart is split across multiple pages or sections. It helps to connect different parts of the flowchart.

Flowchart Example
Example 1: Adding Two Numbers
Here is a flowchart that adds two numbers:

6
Start

Input A

Input B

SUM = A + B

Output SUM

End

This flowchart represents the following steps:


• Start the process.
• Input two numbers A and B.
• Calculate the sum SU M = A + B.

• Output the sum.


• End the process.

Example 2: Find the Maximum of Two Numbers


Below is a flowchart that finds the maximum of two numbers:

7
Start

Input A

Input B

A > B?

no
yes

MAX = A MAX = B

Output MAX

End

This flowchart demonstrates the following steps:


• Start the process.

• Input two numbers A and B.


• Check if A > B.
• If yes, set M AX = A; if no, set M AX = B.
• Output the maximum value.

• End the process.

Advantages of Flowcharts
1. Visual Representation: Flowcharts provide a visual representation of the algorithm, making it easier
to understand and follow.
2. Clear Communication: They improve communication between team members by visually expressing
the flow of processes.
3. Easy Debugging: Errors in logic can be easily identified in flowcharts, helping in quick debugging.

8
4. Simplifies Complex Processes: Complex processes can be broken down into simpler steps, making
the workflow easy to follow.
5. Standardized Format: Flowcharts follow a standardized format, making them universally under-
stood.
6. Helpful in Documentation: They are useful for documenting processes in software development
and business processes.

1.2 Organization of a Computer

Parts of the Computer:

• CPU (Central Processing Unit):


– Registers (R0 to R31): Small, high-speed storage locations within the CPU that temporarily
hold data and instructions. These are used for arithmetic, logical, and data movement operations.
– ALU (Arithmetic Logic Unit): Performs arithmetic operations (e.g., addition, subtraction)
and logical operations (e.g., AND, OR, NOT). It is the core component for processing instructions.
• Main Memory (RAM):
– RAM (Random Access Memory): Temporary storage for data and instructions currently
being used by the CPU. RAM is faster than secondary memory but is volatile (data is lost when
power is off).
– Memory Cells: Represent locations in memory where variables (e.g., a, b, and c) are stored.

9
• Secondary Memory (Disk):
– Used for long-term storage of data and programs. Data is loaded into RAM before being accessed
by the CPU.
• I/O Devices (Input/Output Devices):

– Input Devices: Devices like the keyboard and mouse that send data to the computer.
– Output Devices: Devices like the monitor that display data or results to the user.

Von Neumann Architecture is a computing architecture that uses the Stored Program Concept,
where both instructions and data are stored together in the same memory.
The Stored Program Concept means the program (instructions) is represented as binary code and
resides in memory alongside the data. This allows flexibility, as the program can modify itself, enabling
advanced computation like loops and conditional statements.
This design allows the CPU to fetch and execute instructions sequentially, making it foundational for
modern computers.

1.3 Linux File System Organization

The Linux file system is organized in a hierarchical structure, resembling an upside-down tree with the
root (/) at the top. All directories, files, and devices are stored within this structure. Key directories include:

• / (root): The topmost directory in the Linux file system. Everything begins here.

• /bin: Contains essential user command binaries (executables) required for minimal system operations.
• /boot: Holds boot loader files, such as kernel images.
• /dev: Stores device files representing hardware components.
• /etc: Contains system-wide configuration files and shell scripts that control system startup.

• /home: User home directories, where personal files are stored.


• /lib: Essential shared libraries and kernel modules.
• /media: Mount points for removable media (e.g., USB drives, CD-ROMs).

10
• /mnt: Temporarily mounted file systems.
• /opt: Optional software packages not part of the default installation.
• /proc: Virtual file system containing runtime system information (e.g., system memory, CPU).
• /root: The home directory for the root user.

• /tmp: Temporary files usually deleted upon system reboot.


• /usr: Secondary hierarchy for user data, typically larger programs and utilities.
• /var: Variable data files, such as logs and databases.

1.3.1 Paths
Paths in Linux define the location of a file or directory in the file system. There are two types of paths:
absolute and relative.
Absolute Paths

An absolute path is the full, precise location or address of a file or directory in a computer’s file system,
starting from the root directory. Unlike relative paths, which are based on the current working directory, an
absolute path gives a complete reference to the file or folder, regardless of your current location.

Key Features of Absolute Paths:


1. Starts from the Root Directory: On Unix/Linux systems, the root directory is represented by /.
On Windows systems, it starts with the drive letter (e.g., C:\).
2. Unambiguous: Since an absolute path always includes the root, it is unique and always leads to the
same file or folder, regardless of your current working directory.

11
3. Platform-Specific Syntax: Unix/Linux systems use forward slashes (/) to separate directories, while
Windows systems use backslashes (\).

Example of Absolute Paths


/home/user/documents/report.pdf
• / is the root directory.

• /home/ is a directory inside the root.


• /user/ is a subdirectory of /home/.
• /documents/ is a subdirectory of /user/.
• report.pdf is the file located in the documents directory.

When to Use Absolute Paths


• Script execution or configuration files: Absolute paths ensure scripts or programs find the required
file regardless of where they are run.
• Reliability: Since absolute paths always point to the same location, they are reliable for referencing
files across different directories.

Pros and Cons of Absolute Paths


Pros:
• Always accurate and unambiguous.
• Provides clarity by specifying the complete file location.
Cons:

• Long and cumbersome, especially in deep directory structures.


• Hard-coded paths may break on different systems or environments.
Relative Paths
A relative path refers to the location of a file or directory relative to the current working directory (the
folder you’re currently in).

Key Features of Relative Paths:


1. Relative to Current Directory: The path is determined by the location of the current working
directory.
2. Shorter and Flexible: Relative paths tend to be shorter and more convenient, especially within
projects or common directories.
3. Special Symbols: . refers to the current directory, and .. refers to the parent directory (one level
up).

Example of Relative Paths


If you are in the /home/user/ directory and want to access a file in /home/user/documents/report.pdf,
the relative path would be:

documents/report.pdf

12
Special Symbols in Relative Paths
• . Refers to the current directory.
• .. Moves one level up in the directory tree.
• ../../file.txt Goes up two directory levels to access file.txt.

When to Use Relative Paths


• Within Projects: Convenient for files in a known structure, like a project with subdirectories.
• Portability: Relative paths are portable across different systems or directories as long as the internal
structure remains the same.

Pros and Cons of Relative Paths


Pros:
• Shorter and more concise.
• Portable and flexible within the same project.
Cons:
• Can be confusing in unfamiliar file systems.
• Dependent on the current working directory.

1.3.2 Example Comparison: Absolute vs. Relative Paths


Assume you are in the directory /home/user/ and want to access a file located in /home/user/documents/report.pdf.

• Absolute Path: /home/user/documents/report.pdf


• Relative Path: documents/report.pdf

Relative paths are shorter and simpler when navigating from the current directory.

13
1.4 Basic Commands and Options
Here are some essential Linux commands to help you get started with file and system management.

1.4.1 ls - List Directory Contents


The ls command lists files and directories in the current directory.
Example:
1 ls

Output:
1 Desktop Documents Downloads Music Pictures Videos

Options:
• ls -l: List in long format (shows file permissions, owner, size, and date).

• ls -a: Show hidden files (files starting with .).


Example with Options:
1 ls - la

Output:
1
2 drwxr - xr - x 2 user user 4096 Oct 15 10:32 .
3 drwxr - xr - x 3 user user 4096 Oct 15 10:30 ..
4 -rw -r - -r - - 1 user user 220 Oct 15 10:31 . bashrc
5 -rw -r - -r - - 1 user user 120 Oct 15 10:32 file . txt

1.4.2 mkdir - Make Directory


Creates a new directory.
Example:
1 mkdir new_folder

1.4.3 man - Show Manual for a Command


Displays the manual page for a command, explaining its options and usage.
Example:
1 man ls

1.4.4 cd (change directory)


The cd (change directory) command is used to navigate between directories in the Linux file system. It
allows you to move to a different directory either by specifying its exact location (absolute path) or its
location relative to the current working directory (relative path).

1.4.5 Using Absolute Paths


An absolute path specifies the full location of a directory, starting from the root directory (/). It provides
a complete and unambiguous path to the desired location, regardless of your current working directory.

Syntax:

1 cd / path / to / directory

14
Examples:
1. Navigate to the Documents directory located in the home directory of a user named john:
1 cd / home / john / Documents

2. Navigate to the /var/log directory:


1 cd / var / log

Key Points:
• Absolute paths always start with / (the root directory).
• They are independent of your current location in the file system.

1.4.6 Using Relative Paths


A relative path specifies the location of a directory relative to your current working directory. It is more
concise but depends on your current position in the file system.

Syntax:

1 cd relative / path / to / directory

Examples:
1. Assume your current working directory is /home/john. To navigate to the Documents directory inside
john’s home directory:
1 cd Documents

2. Move up one directory level from /home/john/Documents to /home/john:


1 cd ..

3. Navigate to the Pictures directory inside /home/john/Documents:


1 cd ../ Pictures

Special Symbols for Relative Paths:


• .: Refers to the current directory.

• ..: Refers to the parent directory (one level up).

Comparison of Absolute and Relative Paths

1.4.7 Practical Use Cases


Example 1: Using Absolute Path
If you’re in /var/log and want to navigate to Documents in john’s home directory:
1 cd / home / john / Documents

15
Feature Absolute Path
Relative Path
Definition Full location starting from root (/).
Location relative to the current directory.
Example Path /home/john/Documents
Documents (if in /home/john).
Simplicity Always clear and unambiguous.
Shorter and easier to use for nearby locations.
Dependency Independent of the current directory.
Dependent on the current directory.

Table 1: Comparison of Absolute and Relative Paths

Example 2: Using Relative Path


If you’re already in /home/john, you can navigate to Documents with:
1 cd Documents

Tips for Efficient Navigation

• Use cd / to move directly to the root directory.


• Use cd or simply cd to navigate to your home directory.
• Use cd - to return to the previous directory.

1.4.8 touch - Create an Empty File


Creates an empty file.
Example:
1 touch newfile . txt

1.4.9 cat - Concatenate and Display File Content


Displays the contents of a file.
Example:
1
2 cat file . txt

Output:
1 This is the content of the file .

1.4.10 Using gedit on Linux


gedit is a simple and user-friendly text editor available on Linux systems. It is part of the GNOME desk-
top environment and supports features like syntax highlighting, line numbering, and plugins for additional
functionality. It is ideal for editing configuration files, scripts, and even writing code.

Launching gedit
To open gedit, use the terminal or the application menu:
1 gedit

This opens a blank text editor window where you can start typing.

16
Opening a File
You can open an existing file by specifying its path:
1 gedit filename . txt

Example: To open a file named notes.txt in the current directory:


1 gedit notes . txt

Creating a New File


To create and open a new file:
1 gedit newfile . txt

This opens gedit with a blank editor where you can write and save your content.

Running in the Background


You can run gedit in the background so your terminal remains free:
1 gedit filename . txt &

Saving a File
Once you’ve made your changes, save the file by clicking Save or using the shortcut Ctrl+S.

Exiting gedit
To close gedit, use the Close button or the shortcut Ctrl+Q.

Advantages of Using gedit


• Simple and easy to use.

• Supports syntax highlighting for programming languages.


• Allows plugin support for additional features.
• Suitable for both beginners and advanced users for quick edits.

Summary
gedit is a powerful yet lightweight text editor for Linux users. Its simplicity makes it an excellent choice
for day-to-day text editing, configuration file changes, or quick programming tasks.

1.4.11 cp - Copy Files or Directories


The cp (copy) command is used to copy files or directories from one location to another. It allows you to
copy files between directories, preserve file attributes, and even copy entire directories recursively.

17
Using Absolute Paths with cp
An absolute path specifies the full location of a file or directory, starting from the root directory (/). It
provides a complete path to the file or directory being copied.
Syntax:
1 cp / path / to / source / path / to / destination

Example 1: Copy a file to another directory using absolute paths:


1 cp / home / user / file . txt / home / user / Documents /

In this example: - The source file file.txt is located in /home/user/. - The file is copied to the
/home/user/Documents/ directory.
Example 2: Copy a directory and its contents recursively:
1 cp -r / home / user / source_dir / home / user / de s ti na ti o n_ di r

The −r flag is used to copy directories recursively. In this case, the entire directory source dir and its
contents are copied to destination dir.

Using Relative Paths with cp


A relative path specifies the location of a file or directory relative to the current working directory. It is
shorter and more convenient when working within a known directory structure.
Syntax:
1 cp source_file d e s t i n a t i o n _ d i r e c t o r y

Example 1: Copy a file using relative paths:


1 cp file . txt Documents /

If the current working directory is /home/user/, the file file.txt is copied to the Documents/ directory
inside the same directory.
Example 2: Copy a file to the parent directory:
1 cp file . txt ../

This copies file.txt to the parent directory of the current working directory.

1.4.12 mv - Move or Rename Files or Directories


The mv (move) command is used to move or rename files and directories. It allows you to change the location
of a file or rename it, or even move it between different file systems.

Using Absolute Paths with mv


Like cp, the mv command can also be used with absolute paths to specify the exact location of the source
and destination.
Syntax:
1 mv / path / to / source / path / to / destination

Example 1: Move a file to another directory using absolute paths:


1 mv / home / user / file . txt / home / user / Documents /

In this example: - The file file.txt is moved from the source directory /home/user/ to the destination
directory /home/user/Documents/. - The file is removed from the original location after being moved.
Example 2: Rename a file using absolute paths:
1 mv / home / user / old_name . txt / home / user / new_name . txt

In this case: - The file old name.txt is renamed to new name.txt within the same directory /home/user/.

18
Using Relative Paths with mv
The mv command can also be used with relative paths, which simplifies the process when the source and
destination are within the same directory structure.
Syntax:
1 mv source_file d e s t i n a t i o n _ d i r e c t o r y

Example 1: Move a file using relative paths:


1 mv file . txt Documents /

If the current working directory is /home/user/, this command moves file.txt into the Documents/ direc-
tory.
Example 2: Rename a file using relative paths:
1 mv old_name . txt new_name . txt

This renames the file old name.txt to new name.txt in the current working directory.
Example 3: Move a file to the parent directory:
1 mv file . txt ../

This moves file.txt to the parent directory of the current working directory.

Conclusion
The cp and mv commands are essential tools for managing files and directories in Linux. Understanding how
to use these commands with both absolute and relative paths enhances your ability to efficiently manage
files and directories in different locations within the file system.

1.4.13 rm - Remove Files or Directories


Deletes files or directories.
Example:
1 rm file . txt

Options:
• rm -r: Remove directories and their contents recursively.
Example:
1 rm -r new_folder

1.4.14 grep - Search for a Pattern in Files


The grep command in Linux is used to search for a specific pattern (string or regular expression) within files.
It outputs the lines that contain the pattern, making it an essential tool for text processing and analysis.

Using grep with the -i Option


The -i option makes the search case-insensitive. This means that grep will match the pattern regardless of
whether the characters are uppercase or lowercase.
Syntax:
1 grep -i " pattern " filename

Example: Search for ”hello” in file.txt without considering case:


1 grep -i " hello " file . txt

This command will match hello, Hello, HELLO, or any case variation of the word.

19
Using grep with the -n Option
The -n option is used to display the line numbers along with the matching lines. This is helpful for locating
the exact position of the matched pattern within a file.
Syntax:
1 grep -n " pattern " filename

Example: Search for ”hello” in file.txt and display line numbers:


1 grep -n " hello " file . txt

Output:
1 2: hello world
2 5: Hello again
3 8: HELLO there

Here, grep shows the line numbers where the pattern ”hello” appears.

Using grep with the -c Option


The -c option counts the number of matching lines in the file, rather than displaying the lines themselves.
This is useful when you just need to know how many times a pattern appears.
Syntax:
1 grep -c " pattern " filename

Example: Count how many lines in file.txt contain the word ”hello”:
1 grep -c " hello " file . txt

Output:
1 3

This indicates that the word ”hello” appears in 3 lines of the file.

Using grep with the -v Option


The -v option inverts the search, meaning that grep will display lines that do not contain the specified
pattern. This is useful when you want to exclude certain lines from the output.
Syntax:
1 grep -v " pattern " filename

Example: Display all lines in file.txt that do not contain the word ”hello”:
1 grep -v " hello " file . txt

Output:
1 This is a sample text .
2 Another line that doesn ’t contain hello .
3 Yet another example here .

In this example, grep outputs lines that do not contain the word ”hello.”

Combining Multiple Options


You can combine multiple options in a single grep command. For example, you can search for a pattern
case-insensitively, show the line numbers, and count the occurrences all at once.
Example: Combine -i, -n, and -c to perform a case-insensitive search and count occurrences with line
numbers:
1 grep - in -c " hello " file . txt

20
Summary of Common grep Options
• -i: Perform a case-insensitive search.
• -n: Show line numbers with the matching lines.

• -c: Count the number of matching lines.


• -v: Invert the search to show lines that do not match the pattern.

Using the grep Command with ^ and $


The grep command is used to search for patterns within files. The symbols ^ and $ are special characters
used in regular expressions to match the start and end of a line, respectively.

The ^ Symbol: Match the Start of a Line


The ^ symbol is used to match the beginning of a line. For example, to match lines that start with the word
”start”:

grep ’^start’ filename

This command will return all lines in the file filename that begin with the word ”start”.

The $ Symbol: Match the End of a Line


The $ symbol is used to match the end of a line. For example, to match lines that end with the word ”end”:

grep ’end$’ filename

This command will return all lines in the file filename that end with the word ”end”.

Matching Exact Lines


You can combine both ^ and $ to match lines that exactly equal a specific string. For example, to match
lines that are exactly ”exact”:

grep ’^exact$’ filename

This will return all lines in the file filename that contain exactly the word ”exact”, with no additional
characters before or after.

Example
Let’s consider a file example.txt with the following contents:

apple
banana
apple pie
pie apple

Here are some grep examples using ^ and $:

• To match lines that start with ”apple”:

grep ’^apple’ example.txt

21
Output:

apple
apple pie

• To match lines that end with ”pie”:

grep ’pie$’ example.txt

Output:

apple pie
pie apple

• To match lines that are exactly ”apple”:

grep ’^apple$’ example.txt

Output:

apple

By using these options, grep becomes a powerful and versatile tool for searching text files and filtering data
in Linux.

1.4.15 Understanding the chmod Command in Linux


The chmod (change mode) command in Linux is used to modify file or directory permissions. Permissions
determine who can read, write, or execute a file or directory, ensuring secure and controlled access.
Each file and directory has three types of permissions and applies to three categories of users:

• Permissions:
– Read (r): Allows viewing the contents of a file or listing a directory’s contents.
– Write (w): Allows modifying a file or creating/deleting files in a directory.
– Execute (x): Allows running the file as a program or accessing a directory.
• User Categories:
– Owner (u): The user who owns the file.
– Group (g): A group of users who share access to the file.
– Others (o): All other users on the system.


Octal (Numeric) notation with Examples
In octal mode, permissions are represented using a three-digit number, where each digit corresponds to
the permissions for the owner, group, and others.

22
Octal Values for Permissions
Examples
1. Give full permissions to the owner, read and execute permissions to the group, and read-only to others:
1 chmod 754 file . txt

The command chmod 754 file.txt sets the permissions for the file file.txt using the octal represen-
tation 754. Each digit in 754 corresponds to specific permissions for the owner, group, and others.

Breaking Down 754


The three digits in 754 represent:
• 7 (Owner Permissions): The first digit applies to the file owner.
• 5 (Group Permissions): The second digit applies to the group associated with the file.
• 4 (Other Permissions): The third digit applies to all other users.
Each digit is the sum of the following permission values:
• 4 (Read - r)
• 2 (Write - w)
• 1 (Execute - x)

Detailed Permissions for 754


1. Owner (7): rwx
• 4 (Read) + 2 (Write) + 1 (Execute) = 7
• The owner has full permissions: can read, write, and execute the file.

23
2. Group (5): r-x
• 4 (Read) + 0 (No Write) + 1 (Execute) = 5
• The group can read and execute the file but cannot modify it.
3. Others (4): r--
• 4 (Read) + 0 (No Write) + 0 (No Execute) = 4
• Others can only read the file but cannot modify or execute it.

Resulting Permissions
After running the command chmod 754 file.txt, the permissions for the file file.txt will appear as:
1 - rwxr - xr - -

• rwx: Owner permissions (read, write, execute).


• r-x: Group permissions (read, execute).
• r--: Other permissions (read-only).

Verification
To verify the permissions, use the ls -l command:
1 ls -l file . txt

Example Output:
1 - rwxr - xr - - 1 user group 1234 Nov 26 12:00 file . txt

This confirms that the file has been correctly assigned the permissions 754.

Practical Use Case


The chmod 754 file.txt command is typically used when:
• The file owner needs full control (read, write, execute).
• The group members only need to read and execute the file.
• Other users are limited to read-only access.

Summary
The chmod 754 file.txt command is a powerful way to manage file permissions, ensuring appropriate
access for the owner, group, and others. By understanding the octal representation, you can easily configure
permissions for various use cases.
OutPut
2. Make a file readable, writable, and executable by everyone:
1 chmod 777 script . sh

3. Restrict all permissions for others:


1 chmod 770 directory

24
1.4.16 Symbolic Notation with Examples
In symbolic notation, permissions are represented using characters and operators. This mode is more de-
scriptive and often easier to use for specific changes.

Syntax

1 chmod [ who ][ operator ][ permissions ] filename

• Who:
– u: Owner (user)
– g: Group
– o: Others

25
– a: All (owner, group, others)
• Operator:
– +: Adds a permission.
– -: Removes a permission.
– =: Sets the specified permission and removes others.
• Permissions:
– r: Read
– w: Write
– x: Execute

Examples
1. Add execute permission for the owner:

1 chmod u + x script . sh

26
Output

2. Remove write permission for the group:


1 chmod g - w file . txt

Output

27
3. Set read-only permission for others:
1 chmod o = r file . txt

Output

4. Set full permissions for all:


1 chmod a = rwx file . txt

Output

Example Output:
1 - rwxr - xr - - 1 user group 1234 Nov 25 12:00 file . txt

Explanation of the output:


• -: Indicates a file (directories are represented by d).

28
• rwx: Owner permissions (read, write, execute).
• r-x: Group permissions (read, execute).
• r--: Permissions for others (read-only).

1.4.17 ps - Show Running Processes


The ps command in Linux is used to display information about active processes, including their IDs, memory
usage, CPU usage, and more. It is a vital tool for system monitoring and process management.

Using ps with the -e Option


The -e option (or --everyone) shows all processes running on the system. This includes processes running
under different users, not just the ones owned by the current user.
Syntax:
1 ps -e

Example: Display all processes running on the system:


1 ps -e

Output:
1 PID TTY TIME CMD
2 1 ? 00:00:05 systemd
3 2 ? 00:00:00 kthreadd
4 3 ? 00:00:00 rcu_gp
5 4 ? 00:00:00 rcu_par_gp
6 5 ? 00:00:00 kworker /0:0 H
7 6 ? 00:00:00 mm_percpu_wq
8 ...

Here: - PID: Process ID - TTY: Terminal type - TIME: Cumulative CPU time used by the process - CMD:
Command that started the process
The ps -e command provides a list of all running processes, including system and background processes.

Using ps with the -A Option


The -A option is similar to -e in that it shows all processes. Both options display every process running on
the system, but the -A option is more commonly used as a shorthand for --all.
Syntax:
1 ps -A

Example: Display all processes running on the system:


1 ps -A

Output:
1 PID TTY TIME CMD
2 1 ? 00:00:05 systemd
3 2 ? 00:00:00 kthreadd
4 3 ? 00:00:00 rcu_gp
5 4 ? 00:00:00 rcu_par_gp
6 5 ? 00:00:00 kworker /0:0 H
7 6 ? 00:00:00 mm_percpu_wq
8 ...

The output is the same as ps -e, displaying every process in the system, whether it is initiated by a user
or the system itself.

29
Key Differences Between -e and -A
Both -e and -A display all the processes, but in some Linux distributions or older versions, -e might be
preferred for compatibility. In most modern systems, -A is the more common shorthand.

• -e: Shows all processes (compatibility with older systems).


• -A: A more commonly used shorthand for -e.

Additional Useful Options with ps


You can combine -e or -A with other options to get more detailed information:

• -f: Full format, showing additional information like parent process ID (PPID).
• -u: Show processes for a specific user.
• -l: Long format, displaying more detailed information.

Example: Display all processes with detailed information using -f:


1 ps - Af

Conclusion
The ps command with the -e or -A option is essential for viewing all running processes in the system.
By using it in combination with other options like -f or -l, you can obtain detailed insights into system
performance and active processes.

1.4.18 top - Display Linux Tasks (System Monitoring)


The top command is a powerful tool for real-time monitoring of running processes and system resource usage
in Linux. It provides information about CPU and memory usage, process IDs, uptime, load averages, and
more.

How to Use the top Command


To start monitoring system tasks, simply type:
1 top

This launches the top interface, which updates in real-time. To exit top, press q.

Example Input and Output


Input:
1 top

Example Output:
1 top - 12:30:45 up 5 days , 3:12 , 2 users , load average : 0.15 , 0.10 , 0.05
2 Tasks : 125 total , 1 running , 124 sleeping , 0 stopped , 0 zombie
3 % Cpu ( s ) : 2.0 us , 1.0 sy , 0.0 ni , 97.0 id , 0.0 wa , 0.0 hi , 0.0 si , 0.0 st
4 KiB Mem : 8123456 total , 2048576 free , 3048576 used , 3026304 buff / cache
5 KiB Swap : 2048576 total , 2048576 free , 0 used . 4026536 avail Mem
6
7 PID USER PR NI VIRT RES SHR S % CPU % MEM TIME + COMMAND

30
8 1234 root 20 0 162584 8044 6932 S 0.7 0.1 0:00.23 sshd
9 5678 user 20 0 1123596 126856 61224 S 0.3 1.6 1:15.43 firefox
10 9101 user 20 0 546788 34224 19100 S 0.3 0.4 0:10.87 gnome - terminal
11 4321 root 20 0 40248 5764 4212 S 0.0 0.1 0:00.05 systemd

Explanation of the Output


The top command output is divided into sections:

• System Overview: Displayed at the top of the screen.


– 12:30:45: Current system time.
– up 5 days, 3:12: System uptime (5 days, 3 hours, 12 minutes).
– 2 users: Number of logged-in users.
– load average: 0.15, 0.10, 0.05: System load averages over the last 1, 5, and 15 minutes.
• Task Summary:
– Tasks: 125 total: Total number of processes.
– 1 running: Processes actively running.
– 124 sleeping: Processes waiting for execution.
– 0 stopped: Processes that are stopped.
– 0 zombie: Zombie processes (terminated but not reaped).
• CPU Usage:
– 2.0 us: Percentage of CPU used by user processes.
– 1.0 sy: Percentage of CPU used by system (kernel) processes.

31
– 97.0 id: Percentage of CPU idle.
• Memory Usage:
– 8123456 total: Total physical memory in kilobytes.
– 2048576 free: Free memory available for use.
– 3048576 used: Memory currently in use.
– 3026304 buff/cache: Memory used for buffers and cache.
• Process List: A table showing details for individual processes:
– PID: Process ID.
– USER: User who owns the process.
– PR: Process priority.
– NI: Nice value (priority adjustment).
– VIRT: Virtual memory used by the process.
– RES: Resident memory (RAM) used.
– SHR: Shared memory.
– S: Process state (e.g., R for running, S for sleeping).
– %CPU: CPU usage percentage.
– %MEM: Memory usage percentage.
– TIME+: Total CPU time consumed.
– COMMAND: Command or program running the process.

Interactive Commands in top


While top is running, you can use various keyboard commands to control its behavior:

• k: Kill a process by specifying its PID.


• r: Renice a process (change its priority).
• h: Display help information.
• q: Quit top.

Practical Use Case


Use top to identify resource-heavy processes and manage them effectively. For example:
• Find processes consuming the most CPU or memory.
• Kill unresponsive processes by pressing k and entering the PID.
• Monitor system load during high-traffic periods.

Conclusion
The top command is an essential system monitoring tool in Linux, providing a real-time view of system
performance and running processes. Its interactive features make it invaluable for managing system resources
efficiently.

32
1.4.19 df - Show Disk Usage
Displays the amount of disk space used and available on the filesystem.
Example:
1 df -h

Output:
1 Filesystem Size Used Avail Use % Mounted on
2 / dev / sda1 100 G 30 G 70 G 30% /

1.5 The Compilation Process


GCC transforms a C program into machine-executable code in several steps:

Figure 1: Processor Components

1. Preprocessing: Handles directives like #include and #define.


2. Compilation: The compiler translates the preprocessed source code into assembly language specific
to the target machine.
3. Assembly: The assembler converts the assembly code into machine code (object code), but it does
not yet link it into an executable.
4. Linking: The linker combines all object files and libraries into a single executable file. It resolves
references between different object files.

33
1.6 Hello World Program in C
1.6.1 Writing the C Code
Create a file named program.c:
1 // program . c
2 # include < stdio .h >
3
4 int main () {
5 printf ( " Hello , World !\ n " ) ;
6 return 0;
7 }

1.6.2 Compiling the Program


The GCC (GNU Compiler Collection) is a powerful and widely used compiler in Linux for C, C++, and
many other programming languages. Understanding the GCC compilation process is crucial for developing
and running programs efficiently.
Compile a simple C file into an executable:
1 gcc program . c -o program

This compiles program.c and produces an executable named program.


Running the Compiled Program Execute the program:
1 ./ program

Output:
1 Hello , World !

34
2 Information Storage and Memory Representation
The study of Information Storage and Memory Representation is crucial for several reasons, partic-
ularly in the context of computer science and programming. Understanding these concepts is essential for
building efficient, reliable, and portable software. Below are the key reasons why this study is vital:

1. Fundamental Understanding of Computer Systems


• Memory representation forms the foundation of how computers store, retrieve, and manipulate
data. Whether you’re working with integers, floating-point numbers, or characters, understanding
how data is represented in memory allows you to design more efficient and effective programs.
• Binary and hexadecimal representations are fundamental because all digital systems, including
computers, use binary (base-2) to represent data. Hexadecimal (base-16) is a more human-
readable format for binary data. Familiarity with these systems helps you understand how com-
puters process information at the lowest levels.
2. Efficient Data Storage and Manipulation

• Understanding signed and unsigned numbers and how negative numbers are represented
(e.g., two’s complement) is critical when dealing with various types of data, such as integers
and real numbers. This knowledge is especially important in low-level systems programming and
optimizing programs for memory and performance.
• Floating Point Representation is particularly important for applications involving scientific
calculations, graphics, and simulations, where precision is key. Understanding the limitations of
floating-point arithmetic (such as rounding errors) can help prevent bugs in applications requiring
exact numerical computations.
3. Optimizing Performance and Resources

• Knowing the differences between data types (like int, float, double, etc.) allows developers to
choose the appropriate type for their specific needs, optimizing memory usage and performance.
For example, using short or unsigned types when the data does not need to be negative can
reduce memory usage and improve processing speed.
• In applications where large datasets or real-time systems are involved, understanding efficient
number representation is crucial to avoid unnecessary memory consumption and ensure high
performance.
4. Understanding Platform and Compiler Differences
• Different platforms (e.g., 32-bit vs. 64-bit) and compilers may handle data representation dif-
ferently. Having a deep understanding of how data types are stored and accessed in memory helps
in writing portable and optimized code that behaves consistently across different environments.
• For example, endian-ness (the byte order used to store data) can affect how multi-byte data is
interpreted. A solid understanding of memory representation helps in writing code that handles
such differences correctly.
5. Debugging and Troubleshooting

• When working with low-level programming or debugging complex applications, it is essential to


understand how the data is laid out in memory. Tools like memory dumps, debuggers, and hex
editors often display memory contents in hexadecimal or binary, so being familiar with these
formats helps in identifying issues.
• Misunderstandings of signed versus unsigned numbers or the two’s complement representation
can lead to hard-to-find bugs, such as incorrect results when performing arithmetic operations.
6. Real-World Applications

35
• The concepts of data types and memory representation are not just theoretical but have di-
rect implications in real-world areas like embedded systems programming, cryptography, network
protocols, file systems, and operating systems.
• For example:
– Char Representation: Essential for text processing, user input, and networking.
– Floating-Point Numbers: Required for applications such as gaming, machine learning,
and scientific computing, where large-scale numerical computations are necessary.

7. Improved Code Reliability


• Understanding binary and hexadecimal representations can prevent errors in handling low-level
data and provide insight into the behavior of hardware when interacting with software.
• Efficient use of signed and unsigned integers and floating point numbers ensures that code does
not unexpectedly overflow, underflow, or lose precision, making the software more reliable and
robust.
8. Enabling Advanced Topics
• This study lays the groundwork for more advanced topics like network programming, file
systems, data compression, cryptography, and graphics programming, where efficient
memory handling and number representation are critical.

2.1 Number System


Data is stored in a computer in the form of 0s and 1s. This is because computers understand only binary
language (which consists of just two digits, 0 and 1). Therefore, for a computer, all data and information
is reduced to numbers. Whether the user stores songs, pictures, numbers, or documents, all information is
treated as binary numbers.
In this chapter, we will learn about the different types of number systems used in computers as well as
different types of codes that convert human language, consisting of numeric and alphanumeric characters,
into machine language (in binary code) which the computer understands.

Representation of Numbers in Radix r


Before considering number systems, let us first understand the base or radix of a number system. The
number of unique digits used to form numbers within a number system is called radix of that system. For
example, in the decimal number system, we use digits 0–9 to form numbers; thus, its radix is 10.
A general number system (N )r of radix r can be represented as follows:

(N )r = dn dn−1 . . . d0 d−1 d−2 . . . d−m = d0 r0 + d1 r1 + · · · + dn rn + · · · + d−m r−m


where:
• r = radix
• di = Digit at position i (m ≤ i ≤ n − 1)

• ri = Weight of position i
• n = Number of integral digits in N
• m = Number of fractional digits in N
Digits in radix r number system include 0, . . . , r − 1.

36
Example
Let us consider a decimal number 234.56. Form the number using the aforegiven radix representation.
At position 0, d0 = 4, r0 = 100 = 1
At position 1, d1 = 3, r1 = 101 = 10
At position 2, d2 = 2, r2 = 102 = 100
At position –1, d−1 = 5, r−1 = 10−1 = 0.1
At position –2, d−2 = 6, r−2 = 10−2 = 0.01
We can form the number using the aforementioned information as follows:

(N )r = dn dn−1 . . . d0 d−1 d−2 . . . d−m

= 100 × 2 + 10 × 3 + 1 × 4 + 0.1 × 5 + 0.01 × 6


= 200 + 30 + 4 + 0.5 + 0.06
= 234.56
Number systems are the technique to represent numbers in the computer system architecture, every
value that you are saving or getting into/from computer memory has a defined number system. Computer
architecture supports following number systems.

• Decimal number system: Decimal number system has only ten (10) digits from 0 to 9. Every number
(value) represents with 0,1,2,3,4,5,6, 7,8 and 9 in this number system. The base of decimal number
system is 10, because it has only 10 digits.
• Binary number system: A Binary number system has only two digits that are 0 and 1. Every number
(value) represents with 0 and 1 in this number system. The base of binary number system is 2, because
it has only two digits.
• Octal number system: Octal number system has only eight (8) digits from 0 to 7. Every number
(value) represents with 0,1,2,3,4,5,6 and 7 in this number system. The base of octal number system is
8, because it has only 8 digits.
• Hexadecimal (hex) number system: A Hexadecimal number system has sixteen (16) alphanumeric
values from 0 to 9 and A to F. Every number (value) represents with 0,1,2,3,4,5,6, 7,8,9,A,B,C,D,E
and F in this number system. The base of hexadecimal number system is 16, because it has 16
alphanumeric values. Here A is 10, B is 11, C is 12, D is 14, E is 15 and F is 16.

Figure 2: Number System.

37
2.2 Binary Number System
Computers are electronic machines that operate using binary logic. These devices use two different values
to represent the two voltage levels (0 V for logic 0 and +5 V for logic 1). Therefore, the two values, 0 and
1, correspond to the two digits used by the binary number system.
The binary number system works like the decimal number system, with the following exceptions:
• While the decimal number system uses base 10, the binary number system uses base 2.
• The decimal number system uses the digits 0 to 9, but the binary number system uses only two digits,
0 and 1.

Important Terms in Binary Number System


• Bit is the short form of ‘binary digit’. It is the smallest possible unit of data. In computerized data,
a bit can be either 0 or 1.
• Nibble is a group of four bits.
• Byte is a group of eight bits. A nibble is a half byte. Bits 0–3 are called the low-order nibble, and bits
4–7 form the high-order nibble.
Table 2 lists these terms in the binary number system with examples.

Table 2: Some important terms in the binary number system


Term Size (bits) Example
Bit 1 0
Nibble 4 1010
Byte 8 0101 1100

Binary Representation with Different Numbers of Bits


Now let us understand how much data can be encoded in binary form using different numbers of bits. If we
have a single bit, we can represent only 21 = 2 values, 0 or 1. With two bits, we can represent 22 = 4 values,
namely 00, 01, 10, and 11. Tables 3 and 4 illustrate this concept.

Binary Representation with Two Bits

Table 3: Binary representation with two bits


Decimal value Binary value
0 00
1 01
2 10
3 11

Binary Representation with Three Bits

Table 4: Binary representation with three bits


Decimal value Binary value Decimal value Binary value
0 000 4 100
1 001 5 101
2 010 6 110
3 011 7 111

38
Binary Representation with Four Bits
The table below illustrates how binary values are represented with four bits. With four bits, we can represent
24 = 16 data values.

Table 5: Binary representation with four bits


Decimal value Binary value Decimal value Binary value
0 0000 8 1000
1 0001 9 1001
2 0010 10 1010
3 0011 11 1011
4 0100 12 1100
5 0101 13 1101
6 0110 14 1110
7 0111 15 1111

Applications of Binary Numbers


• The binary system is best suited to be used with computers, as mechanical and electronic relays
recognize only two states of operation—on/off or closed/open. In the binary number system, character
1 = on = closed circuit = true, and character 0 = off = open circuit = false.
• Binary numbers can be easily translated into electrical impulses.

• The binary system can be effectively used to encrypt messages.


• The binary system is the backbone of the development of computer science and many forms of elec-
tronics. It led to the development of devices such as typewriters, cathode ray tubes, telegraphs, and
transistors.

• Binary number systems are also used in statistical investigations and probability studies to explain
strategy, prove mathematical theorems, and solve puzzles.

2.3 Interconversions
To convert Number system from Decimal Number System to Any Other Base is quite easy; you have to
follow just two steps:
• A) Divide the Number (Decimal Number) by the base of target base system (in which you want to
convert the number: Binary (2), Hexadecimal (16)).

• B) Write the remainder from step 1 as a Least Signification Bit (LSB) to Step last as a Most Significant
Bit (MSB).

2.3.1 Decimal to Binary


Converting a Decimal Number into Binary Form
To convert a decimal number into its binary equivalent, simply divide the decimal number by 2 and then
write down the remainder. Repeat this process until the number cannot be divided by 2 anymore.

39
Example
Convert decimal 13 or (13)10 into its binary equivalent.
Solution

2 13 R
2 6 1
2 3 0
2 1 1
0 1
Now write the result starting from the last remainder obtained. Therefore,

(13)10 = (1101)2

Example
Convert 169 into its binary equivalent.
Solution

40
2 169 R
2 84 1
2 42 0
2 21 0
2 10 1
2 5 0
2 2 1
2 1 0
0 1
Now write the result starting from the last remainder obtained. Therefore,

(169)10 = (1010 1001)2

2.3.2 Binary to Decimal


Converting a Binary Number into Decimal Form
In a binary number, all the columns are powers of 2. Table 6 shows the five least significant digit placeholders.

Table 6: *
Table Five least significant digit place holders
Sixteen’s column Eight’s column Four’s column Two’s column One’s column (LSB)
24 23 22 21 20

Note that, in Table 4.5, all the columns are specified in powers of 2. Hence, in order to convert a binary
number into its decimal equivalent, multiply that placeholder value (power of 2) with the bit, and then add
all the products.

Example
Convert 1101 into a decimal number.
Solution

Decimal number = 1 × 23 + 1 × 22 + 0 × 21 + 1 × 20
=1×8+1×4+0×2+1×1
= 8 + 4 + 0 + 1 = 13

Example
Convert 1010 1001 into a decimal number.
Solution

Decimal number = 1 × 27 + 0 × 26 + 1 × 25 + 0 × 24 + 1 × 23 + 0 × 22 + 0 × 21 + 1 × 20
= 1 × 128 + 0 × 64 + 1 × 32 + 0 × 16 + 1 × 8 + 0 × 4 + 0 × 2 + 1 × 1
= 128 + 0 + 32 + 0 + 8 + 0 + 0 + 1
= 169

41
Procedure
The following steps summarize the procedure to convert a binary number into a decimal number.

1. Step 1: Start with the least significant bit (LSB) and multiply that bit with 20 . Note that any number
raised to 0 is always 1.
2. Step 2: Continue working from right to left. Multiply each bit with an incremental power of 2 (i.e.,
21 , 22 , 23 , 24 , etc.).

Multiply the digit with 2(with place value exponent). Eventually add all the multiplication becomes the
Decimal number.

2.3.3 Decimal to Hexadecimal


To convert a decimal number into its hexadecimal equivalent, simply divide the decimal number by 16 and
then write down the remainder. Repeat this process until it cannot be divided by 16 anymore.

Dec 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Bin 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
Hex 0 1 2 3 4 5 6 7 8 9 A B C D E F

Example
Convert decimal 1239 into its hexadecimal equivalent.
Solution

Divisor Quotient Remainder (R)


16 1239 7
16 77 13 (D in hex)
16 4 —
Now write the result starting from the last remainder obtained. Therefore, (1239)10 = (4D7)16 .
Convert (56789)10 into its hexadecimal equivalent.

42
Solution:
56789 ÷ 16 = 3549 R 5
3549 ÷ 16 = 221 R 13 (D)
221 ÷ 16 = 13 R 13 (D)
13 ÷ 16 = 0 R 13 (D)
Now write the result starting from the last remainder obtained:
(56789)10 = (DDDD)16 .

43
2.3.4 Hexadecimal to Decimal
To convert a hexadecimal number to decimal, multiply the value in each position by its hex weight and add
each value.

Example
Convert 0x312B into its equivalent decimal value.
Solution
Decimal number = 3 × 163 + 1 × 162 + 2 × 161 + 11 × 160

= 3 × 4096 + 1 × 256 + 2 × 16 + 11 × 1
= 12288 + 256 + 32 + 11
= 12587

Example
Convert hexadecimal 123 into decimal.
Solution
Decimal number = 1 × 162 + 2 × 161 + 3 × 160

= 1 × 256 + 2 × 16 + 3 × 1
= 256 + 32 + 3
= 291

2.3.5 Binary to Hexadecimal and vice versa


Converting a Hexadecimal Number into Binary Form

Dec 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Bin 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
Hex 0 1 2 3 4 5 6 7 8 9 A B C D E F
Above table can be used to easily convert a hexadecimal number into its binary equivalent. Simply break
the binary number into 4-bit groups, starting with the least significant bit and substituting each bit into
binary for each hexadecimal digit of the number.
Example: Convert (F 1E)16 into binary equivalent.
Hexadecimal (F 1E)16 = (1111 0001 1110)2 .

Converting a Binary Number into Hexadecimal Form


To convert a binary number into its hexadecimal equivalent, follow these steps:
1. Group the binary digits into 4-bit groups, starting from the least significant bit.
2. Replace each group with its hexadecimal equivalent.

Example: Convert (101101110)2 into hexadecimal.


Binary: (101101110)2 = (16E)16 .

44
2.4 Memory Measurements
In computer science, memory is measured in bytes and its multiples. The commonly used units are:

• 1 Byte = 8 bits
• 1 Kilobyte (1 KB) = 210 bytes = 1024 bytes
• 1 Megabyte (1 MB) = 220 bytes = 1024 × 1024 bytes

• 1 Gigabyte (1 GB) = 230 bytes = 1024 × 1024 × 1024 bytes


• 1 Terabyte (1 TB) = 240 bytes = 1024 × 1024 × 1024 × 1024 bytes

Note: Bytes is represented as B. Bits is represented as b.

Powers of 2 Table
Power of 2 (n) Value (2n )
20 1
21 2
22 4
23 8
24 16
25 32
26 64
27 128
28 256
29 512
210 1024
211 2048
212 4096
213 8192
214 16384
215 32768

Example: Conversion of 512MB


• MB to GB:
1 GB = 1024 MB = 210 MB
Therefore,
512 29
512 MB = = 10 = 2−1 GB = 0.5 GB
1024 2
• MB to Kb:
1 MB = 1024 × 8 Kb = 210 × 23 = 213 Kb
Therefore,
512 MB = 512 × 213 = 29 × 213 = 222 Kb = 4194304 Kb

• MB to Mb:
1 MB = 8 Mb = 23 Mb
Therefore,
512 MB = 512 × 23 = 29 × 23 = 212 Mb = 4096 Mb

45
Example: Conversion of 4 GB
Convert 4 GB to various units:

1. GB to KB:
1 GB = 1024 × 1024 KB = 1048576 KB
Therefore,
4 GB = 4 × 1048576 = 4194304 KB

2. GB to MB:
1 GB = 1024 MB
Therefore,
4 GB = 4 × 1024 = 4096 MB

3. GB to Kb:
1 GB = 1024 × 1024 × 8 Kb = 8388608 Kb
Therefore,
4 GB = 4 × 8388608 = 33554432 Kb

4. GB to Mb:
1 GB = 1024 × 8 Mb = 8192 Mb
Therefore,
4 GB = 4 × 8192 = 32768 Mb

5. GB to Gb:
1 GB = 8 Gb
Therefore,
4 GB = 4 × 8 = 32 Gb

Summary Table for Conversions


From (Unit) To (Unit) Conversion Factor
1 GB 1 KB ×1024 × 1024
1 GB 1 MB ×1024
1 GB 1 Kb ×1024 × 1024 × 8
1 GB 1 Mb ×1024 × 8
1 GB 1 Gb ×8

2.5 Unsigned Numbers


Definition: An unsigned number uses all the available bits to represent non-negative integers only. For an
n-bit number, the range of values is from 0 to 2n − 1, inclusive.

Examples
1. For n = 1:
Possible values: 0, 1

2. For n = 2:
Possible values: 0, 1, 2, 3

3. For n = 3:
Possible values: 0, 1, 2, 3, 4, 5, 6, 7

46
4. For n = 4:
Possible values: 0, 1, 2, . . . , 15

5. For n = n:
Number of values: 2n , Min value: 0, Max value: 2n − 1

Unsigned Numbers Summary Table


No. of Bits (n) Number of Values Min Value Max Value
1 21 = 2 0 1
2 22 = 4 0 3
3 23 = 8 0 7
4 24 = 16 0 15
n 2n 0 2n − 1

2.6 Signed Numbers: Signed magnitude, one’s complement and two’s comple-
ment.
Signed numbers are used in computer systems to represent both positive and negative values. A common
approach to handle signed numbers is by reserving the Most Significant Bit (MSB) as the sign bit.
• If the sign bit is 0, the number is positive.
• If the sign bit is 1, the number is negative.
The remaining bits are used to represent the magnitude of the number. For an n-bit signed number:
• The Least Significant Bit (LSB) represents the smallest place value (e.g., 20 ).
• The Most Significant Bit (MSB) determines the sign of the number.

MSB, LSB, and Sign Bit


Below is a representation of a typical 8-bit signed number, where the MSB is used as the sign bit:

MSB (Sign Bit) LSB

1 0 1 1 0 0 1 0

0 1 2 3 4 5 6 7

Explanation
• The MSB (bit 7) determines the sign:
– 0: Positive number.
– 1: Negative number.
• Bits 6 to 0 represent the magnitude of the number.
• The LSB (bit 0) is the smallest place value, contributing 20 to the magnitude.

Using signed numbers in computer systems enables the representation of both positive and negative
values. The MSB as a sign bit ensures that the sign and magnitude are easily distinguished in binary
representations.

47
2.6.1 Sign-and-Magnitude Representation
Sign-and-magnitude is the simplest technique in which the most significant bit (MSB) is set to 0 for a positive
number or 1 for a negative number. The other bits denote the value or the magnitude of the number.
For example, using 7 bits, numbers from -127 to +127 can be represented (i.e., 27 = 128 combinations).

Decimal Number Binary Equivalent (Sign-and-Magnitude Form)


+0 0000000
+1 0000001
+127 0111111
−0 1000000
−1 1000001
−127 1111111
Table for Sign-and-Magnitude:

No. of Bits (n) Number of Values Min Value Max Value


1 21 = 2 −1 +1
2 22 = 4 −3 +3
3 23 = 8 −7 +7
4 24 = 16 −15 +15
n 2n −(2n−1 − 1) +(2n−1 − 1)

2.6.2 One’s Complement Representation


The one’s complement representation of a negative number is obtained by taking the complement of its
positive counterpart (in binary). For example, to represent -45 in the binary system using one’s complement:

1. Write the binary representation of the number’s positive counterpart (e.g., 45: 00101101).
2. Negate each bit in the binary representation.

Hence:
45 = 00101101 and − 45 = 11010010 (One’s Complement)
Table for One’s Complement:

No. of Bits (n) Number of Values Min Value Max Value


1 21 = 2 −0 +1
2 22 = 4 −1 +1
3 23 = 8 −3 +3
4
4 2 = 16 −7 +7
n 2n −(2n−1 − 1) +(2n−1 − 1)

2.6.3 Two’s Complement Representation


In the two’s complement representation:
1. Take One’s complement.
2. Add 1 to the result.
For example, to represent -54:

Binary representation of + 54 = 00110110Complement each bit: 11001001Add 1 to the result: 11001010

Hence:
−54 = 11001010 (Two’s Complement)

48
Table for Two’s Complement:

No. of Bits (n) Number of Values Min Value Max Value


1 21 = 2 −1 +0
2
2 2 =4 −2 +1
3 23 = 8 −4 +3
4 24 = 16 −8 +7
n 2n −2n−1 +(2n−1 − 1)

Comparison of Number Representations for 4 Bits


Binary (4 bits) Sign-and-Magnitude One’s Complement Two’s Complement
0000 +0 +0 0
0001 +1 +1 +1
0010 +2 +2 +2
0011 +3 +3 +3
0100 +4 +4 +4
0101 +5 +5 +5
0110 +6 +6 +6
0111 +7 +7 +7
1000 −0 −7 −8
1001 −1 −6 −7
1010 −2 −5 −6
1011 −3 −4 −5
1100 −4 −3 −4
1101 −5 −2 −3
1110 −6 −1 −2
1111 −7 −0 −1

• Sign-and-Magnitude:
– Simple to understand but has two representations for zero (+0 and −0), causing ambiguity.
• One’s Complement:
– Fixes the issue of sign representation but still has two representations for zero (+0 and −0).

• Two’s Complement:
– Unique representation for zero and simplifies arithmetic by making subtraction an addition oper-
ation.
• Sign-and-Magnitude Limitation:

– Requires extra hardware to handle the sign bit during arithmetic.


• One’s Complement Limitation:
– Requires carry propagation for arithmetic operations and overflow detection.

• Two’s Complement Advantage:


– Efficient hardware implementation and seamless binary counting for both positive and negative
numbers.

NOTE: Among the three, Two’s Complement eliminates ambiguity, simplifies operations, and allows
efficient use of hardware, which is why it is preferred in modern computing systems.

49
2.7 Char Representation
In the C programming language, the char data type is used to store individual characters. These charac-
ters are internally represented using their corresponding ASCII (American Standard Code for Information
Interchange) values, which are numerical codes assigned to each character.

Key Points about char Representation


• A char in C is a single byte (typically 8 bits) and can store values in the range −128 to 127 (signed)
or 0 to 255 (unsigned), depending on the compiler settings.

• ASCII is a 7-bit encoding system that assigns numeric codes to characters.


• The ASCII table includes:
– Printable characters (e.g., letters, digits, punctuation marks).
– Control characters (e.g., newline, tab, etc.).

• Each character is mapped to a specific numeric value in the ASCII table. For example:
– ’A’ has an ASCII value of 65.
– ’a’ has an ASCII value of 97.
– ’0’ has an ASCII value of 48.

• ASCII values can be used in C to perform arithmetic and logical operations on characters.

Example of Character Representation in C


Here is an example of how characters and their ASCII values are handled in C:

#include <stdio.h>

int main() {
char ch = ’A’;
printf("Character: %c, ASCII value: %d\n", ch, ch);

ch = ’a’;
printf("Character: %c, ASCII value: %d\n", ch, ch);

ch = ’0’;
printf("Character: %c, ASCII value: %d\n", ch, ch);

return 0;
}

Output:

Character: A, ASCII value: 65


Character: a, ASCII value: 97
Character: 0, ASCII value: 48

50
ASCII Table (Selected Characters)
Below is a small subset of the ASCII table:

Character Decimal Value Binary Representation


’A’ 65 01000001
’a’ 97 01100001
’0’ 48 00110000
’ ’ (Space) 32 00100000
\n (Newline) 10 00001010
$ 36 00100100
’*’ 42 00101010

Visualizing ASCII Values


Each character in memory is stored as its binary equivalent. For example, the character ’A’ is stored as:

’A’ → 65 → 01000001 (Binary Representation in 8 Bits)

Applications of ASCII Representation


• String Manipulation: Strings in C are arrays of characters terminated by a null character (’
0’). Each character in the string is stored as its ASCII value.
• Arithmetic on Characters: ASCII values allow arithmetic operations. For example, ’A’ + 1 gives
’B’ (ASCII value 66).
• Control Characters: Non-printable characters like newline (\n) and tab (\t) are used for formatting
output.
The char data type and its ASCII representation form the foundation for handling text in C programming.
By understanding ASCII values, programmers can perform efficient operations on characters and strings.

2.8 Floating Point Representation


The Floating point representation is a way to the encode numbers in a format that can handle very large
and very small values. It is based on scientific notation where numbers are represented as a fraction and an
exponent. In computing, this representation allows for trade-off between range and precision.

2.8.1 Fractional Binary Numbers


To convert a decimal number into its binary form, we need to deal with two parts: the integer part and the
fractional part.

1. Integer Part Conversion


To convert the integer part to binary, repeatedly divide the integer by 2, recording the remainders. The
binary equivalent is the remainders read in reverse order. For example, to convert the integer 13 to binary:

13 ÷ 2 = 6 remainder 1
6 ÷ 2 = 3 remainder 0
3 ÷ 2 = 1 remainder 1
1 ÷ 2 = 0 remainder 1
Reading the remainders in reverse order gives the binary representation:
1310 = 11012

51
2. Fractional Part Conversion
To convert the fractional part to binary, multiply the fractional part by 2 and record the integer part. Repeat
this process until the fractional part becomes 0 or until the desired precision is reached.
For example, to convert 0.625 to binary:

0.625 × 2 = 1.25 (integer part: 1, fractional part: 0.25)


0.25 × 2 = 0.5 (integer part: 0, fractional part: 0.5)
0.5 × 2 = 1.0 (integer part: 1, fractional part: 0.0)
Thus, 0.625 in binary is:
0.62510 = 0.1012

Combining Integer and Fractional Parts


To combine both integer and fractional parts, simply concatenate the two binary results. For the example
of converting 13.625:

13.62510 = 1101.1012

Converting Binary Numbers to Decimal


To convert a binary number to decimal, sum the powers of 2 for the integer part and the negative powers of
2 for the fractional part.

1. Integer Part Conversion


For the integer part, sum the powers of 2 for each bit that is set to 1. For example, to convert the binary
number 11012 to decimal:

11012 = 1 × 23 + 1 × 22 + 0 × 21 + 1 × 20 = 8 + 4 + 0 + 1 = 13

2. Fractional Part Conversion


For the fractional part, sum the negative powers of 2 for each bit that is set to 1. For example, to convert
0.1012 to decimal:

0.1012 = 1 × 2−1 + 0 × 2−2 + 1 × 2−3 = 0.5 + 0 + 0.125 = 0.625

Combining Integer and Fractional Parts


To combine both parts, simply sum the integer and fractional parts. For example, converting the binary
number 1101.1012 :

1101.1012 = 13 + 0.625 = 13.62510

52
Convert 25.375 to Binary
Integer Part: 25
25 ÷ 2 = 12 remainder 1
12 ÷ 2 = 6 remainder 0
6 ÷ 2 = 3 remainder 0
3 ÷ 2 = 1 remainder 1
1 ÷ 2 = 0 remainder 1
Thus, the binary equivalent of 25 is 110012 .
Fractional Part: 0.375

0.375 × 2 = 0.75 (integer part: 0, fractional part: 0.75)

0.75 × 2 = 1.5 (integer part: 1, fractional part: 0.5)


0.5 × 2 = 1.0 (integer part: 1, fractional part: 0.0)
Thus, the binary equivalent of 0.375 is 0.0112 .
Final Result:
25.37510 = 11001.0112

Convert 12.625 to Binary


Integer Part: 12
12 ÷ 2 = 6 remainder 0
6 ÷ 2 = 3 remainder 0
3 ÷ 2 = 1 remainder 1
1 ÷ 2 = 0 remainder 1
Thus, the binary equivalent of 12 is 11002 .
Fractional Part: 0.625

0.625 × 2 = 1.25 (integer part: 1, fractional part: 0.25)

0.25 × 2 = 0.5 (integer part: 0, fractional part: 0.5)


0.5 × 2 = 1.0 (integer part: 1, fractional part: 0.0)
Thus, the binary equivalent of 0.625 is 0.1012 .
Final Result:
12.62510 = 1100.1012

Convert 10110.1012 to Decimal


Integer Part: 101102

101102 = 1 × 24 + 0 × 23 + 1 × 22 + 1 × 21 + 0 × 20 = 16 + 0 + 4 + 2 + 0 = 22

Fractional Part: 0.1012

0.1012 = 1 × 2−1 + 0 × 2−2 + 1 × 2−3 = 0.5 + 0 + 0.125 = 0.625

Final Result:
10110.1012 = 22.62510

53
Convert 110.10112 to Decimal
Integer Part: 1102
1102 = 1 × 22 + 1 × 21 + 0 × 20 = 4 + 2 + 0 = 6
Fractional Part: 0.10112

0.10112 = 1 × 2−1 + 0 × 2−2 + 1 × 2−3 + 1 × 2−4 = 0.5 + 0 + 0.125 + 0.0625 = 0.6875

Final Result:
110.10112 = 6.687510

2.8.2 IEEE 754 format

IEEE 754 Single Precision (32-bit) Conversion


IEEE 754 single precision format is a 32-bit representation of floating-point numbers. It consists of:
• 1 sign bit (S),
• 8 exponent bits (E) with a bias of 127,
• 23 bits for the mantissa (M ) with an implicit leading 1.

The general formula to represent a number is:

V = (−1)S × (1.M ) × 2E−127

Where E is the biased exponent.

Examples 1-3: Decimal to IEEE 754 Hexadecimal


We will convert three decimal values to their IEEE 754 hexadecimal representation.

Example 1: Convert 5.75 to IEEE 754 Hexadecimal


1. Normalization:
5.75 = 1.4375 × 22
So, the mantissa is 1.4375, and the exponent is 2.

2. Biasing: The bias for single precision is 127. The biased exponent is:

2 + 127 = 129

3. Binary Representation: - Mantissa: 1.4375 = 1.01112 , so the mantissa is 01110000000000000000000.


- Exponent: 129 = 100000012 .

4. IEEE 754 Representation (Binary):

0 10000001 01110000000000000000000

5. IEEE 754 Hexadecimal: Convert the binary string to hexadecimal:

0 10000001 01110000000000000000000 becomes 0x40F 00000

54
Example 2: Convert -3.25 to IEEE 754 Hexadecimal
1. Normalization:
−3.25 = −1.625 × 21
So, the mantissa is 1.625, and the exponent is 1.
2. Biasing: The bias for single precision is 127. The biased exponent is:
1 + 127 = 128

3. Binary Representation: - Mantissa: 1.625 = 1.1012 , so the mantissa is 10100000000000000000000.


- Exponent: 128 = 100000002 .
4. IEEE 754 Representation (Binary):
1 10000000 10100000000000000000000

5. IEEE 754 Hexadecimal: Convert the binary string to hexadecimal:


1 10000000 10100000000000000000000 becomes 0xC0800000

Example 3: Convert 2.5 to IEEE 754 Hexadecimal


1. Normalization:
2.5 = 1.25 × 21
So, the mantissa is 1.25, and the exponent is 1.
2. Biasing: The bias for single precision is 127. The biased exponent is:
1 + 127 = 128

3. Binary Representation: - Mantissa: 1.25 = 1.012 , so the mantissa is 01000000000000000000000. -


Exponent: 128 = 100000002 .
4. IEEE 754 Representation (Binary):
0 10000000 01000000000000000000000

5. IEEE 754 Hexadecimal: Convert the binary string to hexadecimal:


0 10000000 01000000000000000000000 becomes 0x40000000

Examples 4-6: IEEE 754 Hexadecimal to Decimal


Now, we will convert three IEEE 754 hexadecimal values back to their decimal representation.

Example 4: Convert IEEE 754 Hexadecimal 0x40F00000 to Decimal


1. Binary Representation: Convert 0x40F 00000 to binary:
0x40F 00000 = 01000000 11110000 00000000 000000002

2. Interpretation: - Sign bit S = 0 (positive number). - Exponent E = 100000012 = 129. - Mantissa:


1.01112 (implicit leading 1).
3. Calculate Decimal Value:
Value = (−1)0 × (1.01112 ) × 2129−127 = 1 × 1.4375 × 22 = 5.75

4. Decimal Value:
5.75

55
Example 5: Convert IEEE 754 Hexadecimal 0xC0800000 to Decimal
1. Binary Representation: Convert 0xC0800000 to binary:

0xC0800000 = 11000000 10000000 00000000 000000002

2. Interpretation: - Sign bit S = 1 (negative number). - Exponent E = 100000002 = 128. - Mantissa:


1.1012 (implicit leading 1).
3. Calculate Decimal Value:

Value = (−1)1 × (1.1012 ) × 2128−127 = −1 × 1.625 × 21 = −3.25

4. Decimal Value:
−3.25

Example 6: Convert IEEE 754 Hexadecimal 0x40000000 to Decimal


1. Binary Representation: Convert 0x40000000 to binary:

0x40000000 = 01000000 00000000 00000000 000000002

2. Interpretation: - Sign bit S = 0 (positive number). - Exponent E = 100000002 = 128. - Mantissa:


1.012 (implicit leading 1).
3. Calculate Decimal Value:

Value = (−1)0 × (1.012 ) × 2128−127 = 1 × 1.25 × 21 = 2.5

4. Decimal Value:
2.5

2.9 Data Types in C: signed char, unsigned char, short, unsigned short, int,
unsigned, long, unsigned long, float, double

56
Data Type Bytes Bits Min Value Max Value Format Specifier Example Declaration and Initialization
signed char 1 8 −27 27 − 1 %c signed char c = ’A’;
unsigned char 1 8 0 28 − 1 %c unsigned char uc = ’B’;
short 2 16 −215 215 − 1 %hd short s = -32000;
unsigned short 2 16 0 216 − 1 %hu unsigned short us = 65000;
int 4 32 −231 231 − 1 %d int i = 2147483647;
unsigned 4 32 0 232 − 1 %u unsigned int u = 4294967295;
long 4 32 −231 231 − 1 %ld long l = -100000L;
unsigned long 4 32 0 232 − 1 %lu unsigned long ul = 3000000000UL;
float 4 32 ∼ 1.2 × 10−38 ∼ 3.4 × 1038 %f float f = 3.14f;
double 8 64 ∼ 2.2 × 10−308 ∼ 1.8 × 10308 %lf double d = 2.71828;

Table 7: C Data Types with Bytes, Bits, Min/Max Values, Format Specifiers, and Examples

• signed char:
– Bits: 8 (1 byte) with 1 sign bit.
– Range: −27 to 27 − 1.
– Format Specifier: %c or %d.
– Example: signed char c = ’A’;.
• unsigned char:
– Bits: 8 (1 byte).
– Range: 0 to 28 − 1.
– Format Specifier: %c or %d.
– Example: unsigned char uc = ’B’;.
• short:

– Bits: 16 (2 bytes) with 1 sign bit.


– Range: −215 to 215 − 1.
– Format Specifier: %hd.
– Example: short s = -32000;.

• unsigned short:
– Bits: 16 (2 bytes).
– Range: 0 to 216 − 1.
– Format Specifier: %hu.
– Example: unsigned short us = 65000;.
• int:
– Bits: 32 (4 bytes) with 1 sign bit.
– Range: −231 to 231 − 1.
– Format Specifier: %d.
– Example: int i = 2147483647;.
• unsigned:
– Bits: 32 (4 bytes).
– Range: 0 to 232 − 1.
– Format Specifier: %u.

57
– Example: unsigned int u = 4294967295;.
• long:
– Bits: 32 (4 bytes) with 1 sign bit.
– Range: −231 to 231 − 1.
– Format Specifier: %ld.
– Example: long l = -100000L;.
• unsigned long:
– Bits: 32 (4 bytes).
– Range: 0 to 232 − 1.
– Format Specifier: %lu.
– Example: unsigned long ul = 3000000000UL;.
• float:

– Bits: 32 (4 bytes) using IEEE 754.


– Range: ∼ 1.2 × 10−38 to ∼ 3.4 × 1038 .
– Format Specifier: %f.
– Example: float f = 3.14f;.

• double:
– Bits: 64 (8 bytes) using IEEE 754.
– Range: ∼ 2.2 × 10−308 to ∼ 1.8 × 10308 .
– Format Specifier: %lf.
– Example: double d = 2.71828;.

58
3 Building Blocks and Conditional Constructs
3.1 Building Blocks of C Language
C programs are constructed using essential components like comments, variables, keywords, and con-
stants. These building blocks form the foundation of any C program.

a. Comments
Comments in C are used to make code more readable and to explain the purpose of specific parts of the
code. They are ignored by the compiler.

• Single-line comments: Begin with //.


• Multi-line comments: Enclosed between /* and */.

Example:
#include <stdio.h>
int main() {
// This is a single-line comment
printf("Hello, World!\n"); /* This is a multi-line comment */
return 0;
}

b. Variables and Identifiers in C


Variables are named memory locations used to store data. A variable must be declared before use, specifying
its type.
Syntax:
<datatype> <variable_name>;
Example:
int age = 25; // Integer variable
float salary = 55000.50; // Floating-point variable
Identifiers in C are names used to identify variables, functions, arrays, etc. There are certain rules and
conventions that need to be followed while creating identifiers:

Rules for Identifiers


• An identifier must begin with a letter (A-Z or a-z) or an underscore ( ).
• The subsequent characters of an identifier can be letters (A-Z or a-z), digits (0-9), or underscores ( ).
• C is case-sensitive, so age and Age are considered different identifiers.
• An identifier cannot be a C keyword (reserved word).
• An identifier should not begin with a digit (0-9).
• Identifiers can be of any length, but it is generally advised to keep them short and meaningful.
• Avoid using underscores ( ) at the beginning of an identifier name as they are often used for system-level
names.

Examples of Valid Identifiers


• age, Salary, my variable, num1, count

59
Examples of Invalid Identifiers
• 123number (cannot start with a digit),
• int (C keyword),

• a@b (special character is not allowed),


• long-10 (hyphen is not allowed).

c. Keywords
Keywords are reserved words in C, each with a predefined meaning. Examples include int, return, for,
while, and if.
Example:

int main() { // ’int’ and ’return’ are keywords


return 0;
}
The following table lists all the keywords that are reserved by the C programming 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

Table 8: C Keywords

• auto: Declares automatic variables, which are local variables by default.

• break: Exits from the innermost loop or switch statement.


• case: Defines a constant that can be used in a switch statement.
• char: Defines a character data type.
• const: Declares constant variables.

• continue: Skips the current iteration of a loop and moves to the next iteration.
• default: Defines the default case in a switch statement.
• do: Starts a do-while loop.

• double: Defines a double-precision floating point data type.


• else: Defines the alternative branch in an if-else statement.
• enum: Defines an enumeration type.
• extern: Declares an external variable or function.

60
• float: Defines a single-precision floating point data type.
• for: Defines a for loop.
• goto: Transfers control to a labeled statement.
• if: Defines a conditional statement.

• int: Defines an integer data type.


• long: Defines a long integer data type.
• register: Declares a register variable, which is stored in CPU registers.

• return: Exits a function and optionally returns a value.


• short: Defines a short integer data type.
• sized: Specifies the size of a data type.
• static: Declares a variable that retains its value across function calls.

• struct: Defines a structure.


• switch: Defines a switch statement for multi-way branching.
• typedef: Creates an alias for a data type.

• union: Defines a union, which stores different data types in the same memory location.
• unsigned: Defines an unsigned data type.
• void: Defines a function that does not return any value.
• volatile: Indicates that a variable’s value may change unexpectedly (e.g., hardware).

• while: Defines a while loop.

d. Constants
Constants are fixed values that do not change during program execution. They can be:
• Integer constants: Whole numbers (e.g., 10, -42).

• Floating-point constants: Numbers with decimals (e.g., 3.14, -2.718).


• Character constants: Single characters enclosed in single quotes (e.g., ’A’, ’1’).
• String literals: Enclosed in double quotes (e.g., "Hello").
Example:

#define PI 3.14159 // Constant using #define


const int MAX = 100; // Constant using ’const’

3.2 Input and Output in C


C provides functions for both formatted and unformatted input/output operations.

61
a. Formatted Input/Output
• Formatted Input: scanf() is used to read input.
• Formatted Output: printf() is used to display output.

Example:
#include <stdio.h>
int main() {
int age;
printf("Enter your age: "); // Prompt user
scanf("%d", &age); // Read integer input
printf("Your age is %d\n", age); // Display integer
return 0;
}

b. Unformatted Input/Output
• Unformatted Input: getchar() and gets() are used for character and string input.
• Unformatted Output: putchar() and puts() are used for character and string output.

Example:
#include <stdio.h>
int main() {
char name[50];
printf("Enter your name: ");
gets(name); // Read string input
puts("Your name is: ");
puts(name); // Display string
return 0;
}

c. Format Specifiers
Format specifiers are used with printf() and scanf() to specify the type of data.

• %d: Integer
• %f: Float

• %c: Character
• %s: String
• %ld: Long Integer
• %lf: Double

• %u: Unsigned Integer

Example:

62
#include <stdio.h>
int main() {
int id = 101;
float salary = 25000.75;
char grade = ’A’;
printf("ID: %d\nSalary: %.2f\nGrade: %c\n", id, salary, grade);
return 0;
}

3.3 Initialization Example


Example:
#include <stdio.h>
int main() {
int a = 10; // Integer initialization
float b = 3.14f; // Float initialization
char c = ’X’; // Character initialization
printf("Integer: %d, Float: %.2f, Character: %c\n", a, b, c);
return 0;
}

3.4 Operators in C
In C programming, operators are used to perform operations on variables and values. Operators can be
categorized into several types based on their functionality and the number of operands they operate on.
This section covers the following categories of operators:

• Assignment Operators
• Unary Operators
• Binary Operators
• Arithmetic Operators
• Relational Operators
• Logical Operators
• Size of Operator
• Type Conversion and Type Casting

3.4.1 Assignment Operators


Assignment operators are used to assign values to variables. The basic assignment operator is the equals
sign (=), but C also provides shorthand operators for common assignments.

• = : Basic assignment operator.


• += : Add and assign.
• -= : Subtract and assign.
• *= : Multiply and assign.
• /= : Divide and assign.

63
• %= : Modulus and assign.

Example:

int a = 5;
a += 10; // a = a + 10
a -= 3; // a = a - 3
a *= 2; // a = a * 2
a /= 4; // a = a / 4

3.4.2 Unary Operators


Unary operators operate on a single operand. These include:

• + : Unary plus (positive).

• - : Unary minus (negation).


• ++ : Increment operator.
• -- : Decrement operator.

• ! : Logical NOT operator.


• & : Address-of operator.
• * : Dereference operator (pointer).

Example:
int a = 10;
int b = 20;
a++; // Increment a by 1
--b; // Decrement b by 1
int* ptr = &a; // Address-of operator
int val = *ptr; // Dereference operator

3.4.3 Binary Operators


Binary operators operate on two operands. These include:

• Arithmetic Operators: +, -, *, /, %.
• Relational Operators: ==, !=, <, >, <=, >=.

• Logical Operators: &&, ||.


• Bitwise Operators: &, |, ^, <<, >>.

Example:
int a = 5, b = 2;
int sum = a + b; // Arithmetic: sum = 7
int product = a * b; // Arithmetic: product = 10
int equal = (a == b); // Relational: equal = 0 (false)
int logical_and = (a > b) && (b < 3); // Logical: logical_and = 1 (true)

64
3.4.4 Arithmetic Operators
Arithmetic operators are used to perform basic arithmetic operations. They include:

• + : Addition.
• - : Subtraction.
• * : Multiplication.

• / : Division.
• % : Modulus (remainder).

Example:
int a = 9, b = 4;
int sum = a + b; // sum = 13
int diff = a - b; // diff = 5
int prod = a * b; // prod = 36
int div = a / b; // div = 2
int rem = a % b; // rem = 1

3.4.5 Relational Operators


Relational operators are used to compare two values. These include:

• == : Equal to.
• != : Not equal to.

• < : Less than.


• > : Greater than.
• <= : Less than or equal to.
• >= : Greater than or equal to.

Example:
int a = 10, b = 20;
bool result1 = (a == b); // result1 = false
bool result2 = (a < b); // result2 = true

3.4.6 Logical Operators


Logical operators are used to perform logical operations. These include:

• && : Logical AND.


• || : Logical OR.
• ! : Logical NOT.

Example:

int a = 5, b = 10;
bool result1 = (a > 2) && (b < 15); // result1 = true
bool result2 = (a > 10) || (b < 15); // result2 = true
bool result3 = !(a < 3); // result3 = true

65
3.4.7 Precedence and Associativity
Operator precedence determines the order in which operators are evaluated in an expression. In C, operators
with higher precedence are evaluated first. If operators have the same precedence, associativity determines
the order.

• Arithmetic operators (+, -, *, /, %) have higher precedence than relational and logical operators.
• *, /, and % have left-to-right associativity.

• +, - have left-to-right associativity.


• Relational and logical operators have left-to-right associativity.

Example:
int a = 5, b = 2, c = 3;
int result = a + b * c; // result = 5 + (2 * 3) = 11 (multiplication has higher precedence)

3.4.8 Size of Operator


The sizeof operator is used to determine the size (in bytes) of a data type or variable.
Example:
int a = 5;
printf("Size of int: %lu\n", sizeof(a)); // Prints the size of int
printf("Size of float: %lu\n", sizeof(float)); // Prints the size of float

3.5 Type Conversion


Type Conversion is the process of converting one data type into another. It can be done automatically or
manually.

Implicit Type Conversion


C automatically converts data from one type to another when it is required in an expression.
Example:
int a = 10;
float b = 20.5;
float result = a + b; // Implicit conversion from int to float

Explicit Type Casting


Explicit type casting involves manually converting a variable from one type to another using a cast operator.
Example:
float a = 9.5;
int b = (int)a; // Explicit cast from float to int (b = 9)

3.6 Conditional Constructs


Conditional constructs in C are used to make decisions based on the evaluation of conditions. These con-
structs allow the program to execute certain parts of code depending on whether a condition is true or
false.

66
1. if Statement
The if statement in C is used to execute a block of code only if a specific condition is true. If the condition
evaluates to true, the code inside the if block is executed; otherwise, it is skipped.
Syntax:
if (condition) {
// Code to be executed if the condition is true
}
Example 1: Simple if statement
#include <stdio.h>

int main() {
int number = 10;

if (number > 5) {
printf("The number is greater than 5.\n");
}

return 0;
}
In this example, the number 10 is greater than 5, so the output will be:
The number is greater than 5.

2. if-else Statement
The if-else statement is used when there are two options: one if the condition is true and another if the
condition is false. If the condition is true, the if block is executed; otherwise, the else block is executed.
Syntax:
if (condition) {
// Code to be executed if the condition is true
} else {
// Code to be executed if the condition is false
}
Example 2: if-else statement
#include <stdio.h>

int main() {
int number = 2;

if (number % 2 == 0) {
printf("The number is even.\n");
} else {
printf("The number is odd.\n");
}

return 0;
}
In this example, since the number is even (2
The number is even.

67
3. Cascading if-else Statement
A cascading if-else statement is used when multiple conditions need to be checked in sequence. The
conditions are checked one after another, and the corresponding block of code is executed for the first true
condition.
Syntax:
if (condition1) {
// Code to be executed if condition1 is true
} else if (condition2) {
// Code to be executed if condition2 is true
} else if (condition3) {
// Code to be executed if condition3 is true
} else {
// Code to be executed if none of the above conditions are true
}
Example 3: Cascading if-else statement
#include <stdio.h>

int main() {
int number = 0;

if (number > 0) {
printf("The number is positive.\n");
} else if (number < 0) {
printf("The number is negative.\n");
} else {
printf("The number is zero.\n");
}

return 0;
}
In this example, the number is zero, so the output will be:
The number is zero.

4. switch Statement
The switch statement is used to execute one of many code blocks based on the value of an expression. It is
often used as an alternative to a series of if-else-if statements when there are multiple conditions to be
checked.
Syntax:
switch (expression) {
case constant1:
// Code to be executed if expression == constant1
break;
case constant2:
// Code to be executed if expression == constant2
break;
// More cases as needed
default:
// Code to be executed if no case matches
}

68
break is used to exit the switch statement once a case is executed. If break is not provided, the program
will ”fall through” and continue checking the subsequent cases.
Example 4: switch statement
#include <stdio.h>

int main() {
int day = 3;

switch (day) {
case 1:
printf("Monday\n");
break;
case 2:
printf("Tuesday\n");
break;
case 3:
printf("Wednesday\n");
break;
case 4:
printf("Thursday\n");
break;
case 5:
printf("Friday\n");
break;
case 6:
printf("Saturday\n");
break;
case 7:
printf("Sunday\n");
break;
default:
printf("Invalid day\n");
}

return 0;
}
In this example, since the value of day is 3, the output will be:
Wednesday

5. switch Statement with Fall-Through


If the break statement is omitted, the program will ”fall through” to the next case, even if the current case
is executed. This can be useful in certain scenarios where multiple cases should share the same block of code.
Example 5: switch without break
#include <stdio.h>

int main() {
int day = 2;

switch (day) {
case 1:
case 2:

69
case 3:
printf("It’s a weekday.\n");
break;
case 4:
case 5:
printf("It’s a weekend.\n");
break;
default:
printf("Invalid day\n");
}

return 0;
}
In this case, since day is 2, the program will print:
It’s a weekday.

Note
if and else are used for simple conditional branching.
else if allows for multiple conditions to be checked in sequence.
switch provides a way to handle multiple possible values for a single expression, making the code more
readable and efficient when there are many conditions to check.

3.7 More Examples


This document contains examples of various operators and conditional constructs in C programming.

1. Assignment Operator Example


Explanation: The assignment operator (=) is used to assign a value to a variable.
Code Example:

#include <stdio.h>

int main() {
int a, b;
a = 10; // Assigning 10 to a
b = a; // Assigning value of a to b

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


return 0;
}
Output:

a = 10, b = 10

2. Unary Operator Example


Explanation: Unary operators operate on a single operand. The example demonstrates the increment
operator.
Code Example:

70
#include <stdio.h>

int main() {
int num = 5;
num++; // Increment operator
printf("num = %d\n", num);
return 0;
}
Output:
num = 6

3. Binary Operator Example


Explanation: Binary operators work on two operands. This example demonstrates the use of the addition
operator.
Code Example:
#include <stdio.h>

int main() {
int a = 5, b = 10, sum;
sum = a + b; // Addition of a and b
printf("Sum = %d\n", sum);
return 0;
}
Output:

Sum = 15

4. Arithmetic Operators Example


Explanation: Arithmetic operators are used to perform mathematical operations. This example uses
addition, subtraction, multiplication, and division.
Code Example:
#include <stdio.h>

int main() {
int a = 15, b = 4;
printf("Addition: %d + %d = %d\n", a, b, a + b);
printf("Subtraction: %d - %d = %d\n", a, b, a - b);
printf("Multiplication: %d * %d = %d\n", a, b, a * b);
printf("Division: %d / %d = %d\n", a, b, a / b);
return 0;
}
Output:
Addition: 15 + 4 = 19
Subtraction: 15 - 4 = 11
Multiplication: 15 * 4 = 60
Division: 15 / 4 = 3

71
5. Relational Operators Example
Explanation: Relational operators are used to compare two values. This example uses the greater than
operator.
Code Example:

#include <stdio.h>

int main() {
int a = 20, b = 10;
if (a > b) {
printf("a is greater than b\n");
} else {
printf("a is not greater than b\n");
}
return 0;
}

Output:
a is greater than b

6. Logical Operators Example


Explanation: Logical operators are used to combine multiple conditions. This example uses logical AND
and OR.
Code Example:
#include <stdio.h>

int main() {
int a = 5, b = 10, c = 20;
if (a < b && b < c) {
printf("Both conditions are true\n");
}

if (a > b || b < c) {
printf("At least one condition is true\n");
}

return 0;
}
Output:
Both conditions are true
At least one condition is true

7. Precedence and Associativity Example


Explanation: Operators have precedence and associativity rules. This example demonstrates operator
precedence and associativity.
Code Example:

#include <stdio.h>

int main() {

72
int a = 5, b = 10, c = 3;
int result = a + b * c; // Multiplication has higher precedence
printf("Result = %d\n", result);
return 0;
}
Output:
Result = 35

8. Sizeof Operator Example


Explanation: The sizeof operator is used to determine the size (in bytes) of a variable or data type.
Code Example:
#include <stdio.h>

int main() {
int num = 10;
printf("Size of int: %lu bytes\n", sizeof(num));
return 0;
}
Output:
Size of int: 4 bytes

9. Type Conversion Example


Explanation: Type conversion is the process of converting a value from one data type to another. This
example demonstrates implicit type conversion.
Code Example:
#include <stdio.h>

int main() {
int a = 5;
double b = 2.5;
double result = a + b; // Implicit conversion of a to double
printf("Result = %.2f\n", result);
return 0;
}
Output:
Result = 7.50

10. Type Casting Example


Explanation: Type casting is explicitly converting a variable from one type to another. This example
demonstrates explicit type casting.
Code Example:
#include <stdio.h>

int main() {
double a = 9.5;
int b = (int) a; // Explicit type casting

73
printf("a = %.2f, b = %d\n", a, b);
return 0;
}
Output:

a = 9.50, b = 9

74
4 Loop Constructs and Arrays
4.1 Loops
A loop is a control structure that allows repeated execution of a block of code. Loops are fundamental for
solving iterative problems and automating repetitive tasks. There are three primary types of loops: FOR,
WHILE, and DO-WHILE, along with Nested Loops for handling complex scenarios.

4.1.1 FOR Loop


The FOR loop is used when the number of iterations is known before the loop starts. It consists of three
parts:

1. Initialization: Initializes the loop control variable.


2. Condition: Checks whether the loop should continue.
3. Update: Updates the loop control variable after each iteration.

Algorithm
1. Set the initial value of the control variable.

2. Check if the condition is true:


• If true, execute the loop body.
• If false, exit the loop.
3. After executing the loop body, update the control variable.

4. Repeat steps 2–3 until the condition is false.

75
Flowchart

Example 1: Printing Numbers from 1 to 5


Code:
#include <stdio.h>
int main() {
for (int i = 1; i <= 5; i++) {
printf("%d ", i);
}
return 0;
}

Trace:

76
Iteration Value of i Condition (i <= 5) Output
1 1 True 1
2 2 True 2
3 3 True 3
4 4 True 4
5 5 True 5
6 6 False -

Example 2: Sum of First 5 Natural Numbers


Code:
#include <stdio.h>
int main() {
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum += i;
}
printf("Sum: %d", sum);
return 0;
}

Trace:
Iteration Value of i Value of sum Condition (i <= 5)
1 1 1 True
2 2 3 True
3 3 6 True
4 4 10 True
5 5 15 True
6 6 - False

Example 3: C Program to Calculate the Sum of First n Natural Numbers Using a For Loop
#include <stdio.h>

int main() {
int n, sum = 0;

// Read the value of n from the user


printf("Enter a number: ");
scanf("%d", &n);

// Calculate the sum of the first n natural numbers


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

// Display the result


printf("The sum of the first %d natural numbers is: %d\n", n, sum);

return 0;
}

77
4.1.2 WHILE Loop
The WHILE loop is used when the number of iterations is not known beforehand. It continues as long as
the condition is true.

Algorithm
1. Initialize the control variable.

2. Check the condition:


• If true, execute the loop body.
• If false, exit the loop.
3. Update the control variable (if required) within the loop body.

4. Repeat steps 2–3.

Flowchart

Example 1: Printing Even Numbers from 2 to 10


Code:

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

78
int i = 2;
while (i <= 10) {
printf("%d ", i);
i += 2;
}
return 0;
}

Trace:
Iteration Value of i Condition (i <= 10) Output
1 2 True 2
2 4 True 4
3 6 True 6
4 8 True 8
5 10 True 10
6 12 False -

Example 2: Calculating Factorial of 5


Code:
#include <stdio.h>
int main() {
int i = 1, factorial = 1;
while (i <= 5) {
factorial *= i;
i++;
}
printf("Factorial: %d", factorial);
return 0;
}

Trace:
Iteration Value of i Value of factorial Condition (i <= 5)
1 1 1 True
2 2 2 True
3 3 6 True
4 4 24 True
5 5 120 True
6 6 - False

Example 3: C program to calculate the factorial of a given number using a while loop.
#include <stdio.h>

int main() {
int num, fact = 1;

// Read the number from the user


printf("Enter a number: ");
scanf("%d", &num);

// Calculate the factorial using a while loop


while (num > 1) {

79
fact = fact * num;
num--;
}

// Display the result


printf("The factorial is: %d\n", fact);

return 0;
}

4.1.3 DO WHILE Loop


The DO-WHILE loop ensures that the loop body executes at least once, even if the condition is false
initially.

Algorithm
1. Execute the loop body.
2. Check the condition:
• If true, repeat the loop body.
• If false, exit the loop.

Flowchart

80
Example 1: Printing Numbers from 1 to 3
Code:
#include <stdio.h>
int main() {
int i = 1;
do {
printf("%d ", i);
i++;
} while (i <= 3);
return 0;
}

Trace:
Iteration Value of i Condition (i <= 3) Output
1 1 True 1
2 2 True 2
3 3 True 3
4 4 False -

Example 2: Reversing a Number


Code:
#include <stdio.h>
int main() {
int num = 123, reverse = 0;
do {
reverse = reverse * 10 + (num % 10);
num /= 10;
} while (num != 0);
printf("Reversed: %d", reverse);
return 0;
}

Trace:
Iteration num reverse Condition (num! = 0)
1 123 3 True
2 12 32 True
3 1 321 True
4 0 - False

Example 3: C program to find the sum of the digits of a given number using a do-while loop.
#include <stdio.h>

int main() {
int num, sum = 0, digit;

// Input a number
printf("Enter a positive integer: ");
scanf("%d", &num);

if (num < 0) {

81
printf("Please enter a positive integer.\n");
return 1;
}

// Calculate the sum of digits using do-while loop


do {
digit = num % 10; // Extract the last digit
sum += digit; // Add the digit to the sum
num /= 10; // Remove the last digit from the number
} while (num > 0);

// Print the result


printf("The sum of the digits is: %d\n", sum);

return 0;
}

4.2 Arrays
An array is a data structure that stores a collection of elements of the same type, arranged in contiguous
memory locations. Arrays are commonly used for organizing data and performing repetitive tasks efficiently.

4.2.1 Array Initialization


Array initialization involves assigning values to an array at the time of its declaration.

Syntax
data_type array_name[size] = {value1, value2, ..., valueN};

Example: Single-Dimensional Array


Code:
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
return 0;
}

Explanation: - The array arr is initialized with 5 values. - Elements can be accessed using their indices,
starting from 0.

Output:

10 20 30 40 50

Partial Initialization
If fewer elements are provided, the remaining elements are initialized to 0 by default.
int arr[5] = {1, 2}; // Remaining elements are set to 0

82
4.2.2 Bounds Checking
C does not perform bounds checking during compilation or runtime. This means that accessing an array
index outside its defined range leads to undefined behavior.

Example: Bounds Violation


Code:

#include <stdio.h>
int main() {
int arr[3] = {1, 2, 3};
printf("%d", arr[5]); // Undefined behavior
return 0;
}

Key Points: - Always ensure array indices remain within the valid range (0 to size-1). - Modern program-
ming languages like Python enforce bounds checking to prevent such issues.

4.2.3 Initializing a 2-Dimensional Array


A 2D array is essentially an array of arrays, with rows and columns.

Syntax
data_type array_name[rows][columns] = {
{value1, value2, ...},
{value3, value4, ...},
...
};

Example: Static Initialization


Code:
#include <stdio.h>
int main() {
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}

Output:
1 2 3
4 5 6

83
Dynamic Initialization
Elements of a 2D array can also be assigned values during runtime.
int matrix[2][2];
matrix[0][0] = 1;
matrix[0][1] = 2;
// And so on...

4.2.4 Memory Map of a 2-Dimensional Array


A 2D array is stored in memory in row-major order by default, meaning the elements of a row are stored
sequentially in memory before the next row begins.

Example
Consider a 2D array:
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

Memory Representation:
Matrix Index (0,0) (0,1) (0,2) (1,0) (1,1) (1,2)
Value 1 2 3 4 5 6
Memory Address 1000 1004 1008 1012 1016 1020
Note: Assuming an integer takes 4 bytes.

Access Formula: For an array matrix[m][n]:

Address of matrix[i][j] = Base Address + (i × Number of Columns + j) × Size of Element

Example Calculation
If Base Address = 1000, the address of matrix[1][2] is:

1000 + (1 × 3 + 2) × 4 = 1000 + 20 = 1020

Note:
• Arrays are fundamental for organizing and accessing data efficiently.
• Proper initialization and bounds checking ensure safe and predictable behavior.
• The memory layout of 2D arrays allows direct computation of addresses for efficient access.

4.3 More Examples


Example1: C program to demonstrate array initialization, bounds checking, and basic opera-
tions with a 2-dimensional array.
#include <stdio.h>

int main() {
// Initialize a 1D array
int array1D[5] = {10, 20, 30, 40, 50};

84
// Initialize a 2D array
int array2D[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

// Display 1D array elements


printf("1D Array Elements:\n");
for (int i = 0; i < 5; i++) {
printf("array1D[%d] = %d\n", i, array1D[i]);
}

// Display 2D array elements


printf("\n2D Array Elements:\n");
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("array2D[%d][%d] = %d ", i, j, array2D[i][j]);
}
printf("\n");
}

// Bounds checking example


printf("\nBounds Checking Demonstration:\n");
int index = 6; // Example index to demonstrate bounds checking

if (index >= 0 && index < 5) {


printf("array1D[%d] = %d\n", index, array1D[index]);
} else {
printf("Index %d is out of bounds for array1D!\n", index);
}

return 0;
}

Sample Output
1D Array Elements:
array1D[0] = 10
array1D[1] = 20
array1D[2] = 30
array1D[3] = 40
array1D[4] = 50

2D Array Elements:
array2D[0][0] = 1 array2D[0][1] = 2 array2D[0][2] = 3
array2D[1][0] = 4 array2D[1][1] = 5 array2D[1][2] = 6

Bounds Checking Demonstration:


Index 6 is out of bounds for array1D!

Example2: Write a C program to add two matrices.


#include <stdio.h>

85
int main() {
int rows, cols, i, j;

// Input the size of matrices


printf("Enter the number of rows and columns: ");
scanf("%d %d", &rows, &cols);

int matrix1[rows][cols], matrix2[rows][cols], result[rows][cols];

// Input elements for the first matrix


printf("Enter elements of the first matrix:\n");
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
scanf("%d", &matrix1[i][j]);
}
}

// Input elements for the second matrix


printf("Enter elements of the second matrix:\n");
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
scanf("%d", &matrix2[i][j]);
}
}

// Add the matrices


for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
result[i][j] = matrix1[i][j] + matrix2[i][j];
}
}

// Display the result


printf("Resultant Matrix:\n");
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
printf("%d ", result[i][j]);
}
printf("\n");
}

return 0;
}

Sample Output
Enter the number of rows and columns: 2 2
Enter elements of the first matrix:
1 2
3 4
Enter elements of the second matrix:
5 6
7 8

86
Resultant Matrix:
6 8
10 12

Example3: Write a C program to add two matrices.


#include <stdio.h>

int main() {
int rows1, cols1, rows2, cols2, i, j, k;

printf("Enter rows and cols of first matrix: ");


scanf("%d %d", &rows1, &cols1);

printf("Enter rows and cols of second matrix: ");


scanf("%d %d", &rows2, &cols2);

if (cols1 != rows2) {
printf("Matrix multiplication not possible.\n");
return 1;
}

int matrix1[rows1][cols1], matrix2[rows2][cols2], result[rows1][cols2];

// Input first matrix


printf("Enter elements of first matrix:\n");
for (i = 0; i < rows1; i++)
for (j = 0; j < cols1; j++)
scanf("%d", &matrix1[i][j]);

// Input second matrix


printf("Enter elements of second matrix:\n");
for (i = 0; i < rows2; i++)
for (j = 0; j < cols2; j++)
scanf("%d", &matrix2[i][j]);

// Multiply matrices
for (i = 0; i < rows1; i++)
for (j = 0; j < cols2; j++) {
result[i][j] = 0;
for (k = 0; k < cols1; k++)
result[i][j] += matrix1[i][k] * matrix2[k][j];
}

// Display result
printf("Resultant Matrix:\n");
for (i = 0; i < rows1; i++) {
for (j = 0; j < cols2; j++)
printf("%d ", result[i][j]);
printf("\n");
}

return 0;
}

87
Sample Output
Enter rows and columns of the first matrix: 2 3
Enter rows and columns of the second matrix: 3 2
Enter elements of the first matrix:
1 2 3
4 5 6
Enter elements of the second matrix:
7 8
9 10
11 12
Resultant Matrix:
58 64
139 154

88
5 Functions, Scope and Storage Class
5.1 Functions
Functions are blocks of code designed to perform specific tasks. They help make code modular, reusable,
and easier to debug. A function is a self-contained block of statements that performs a specific task. In C,
every program must have a main() function, which acts as the entry point.

Advantages of Functions:
• Code reusability
• Better readability and modularity

• Easier debugging and maintenance

5.1.1 Defining and Calling Functions


A function must be defined before it can be used.

Syntax: Function Definition


return_type function_name(parameter_list) {
// Function body
return value; // Optional for void functions
}

Example: Function Definition and Call

1 # include < stdio .h >


2
3 // Function to add two numbers
4 int add ( int a , int b ) {
5 return a + b ;
6 }
7
8 int main () {
9 int x = 10 , y = 20;
10 int result = add (x , y ) ; // Function call
11 printf ( " Sum : % d \ n " , result ) ;
12 return 0;
13 }

Explanation: - add is a function that takes two integers as arguments and returns their sum. - The
function is called in main() with actual arguments x and y.

Output:
Sum: 30

C program to calculate the value of ab using a function.


#include <stdio.h>

// Function to add two numbers


int add(int a, int b) {
return a + b;

89
}

int main() {
int num1, num2, sum;

// Input two numbers


printf("Enter two numbers: ");
scanf("%d %d", &num1, &num2);

// Call the add function


sum = add(num1, num2);

// Display the result


printf("The sum of %d and %d is: %d\n", num1, num2, sum);

return 0;
}

Sample Output
Enter the base and exponent: 2 3
2 raised to the power of 3 is: 8

5.1.2 Function Declaration (Prototype)


A function declaration (or prototype) informs the compiler about the function’s name, return type, and
parameters before its definition.

Syntax
return_type function_name(parameter_list);

Example: Using a Function Prototype

1 # include < stdio .h >


2
3 // Function prototype
4 int multiply ( int a , int b ) ;
5
6 int main () {
7 int result = multiply (3 , 4) ;
8 printf ( " Product : % d \ n " , result ) ;
9 return 0;
10 }
11
12 // Function definition
13 int multiply ( int a , int b ) {
14 return a * b ;
15 }

Output:
Product: 12

5.1.3 Arguments in Functions


Arguments are values passed to a function during its call.

90
Types of Arguments:
• Actual Arguments: Passed during the function call.
• Formal Arguments: Received by the function and used within it.

Pass by Value
In this method, the value of an argument is passed, and changes to the parameter inside the function do not
affect the original value.

1 # include < stdio .h >


2
3 void modify ( int x ) {
4 x = 50; // Changes local to the function
5 }
6
7 int main () {
8 int num = 10;
9 modify ( num ) ;
10 printf ( " Value of num : % d \ n " , num ) ;
11 return 0;
12 }

Output:
Value of num: 10

Pass by Reference
This method passes the memory address of a variable, allowing the function to modify the original value.

1 # include < stdio .h >


2
3 void modify ( int * x ) {
4 * x = 50; // Changes the original value
5 }
6
7 int main () {
8 int num = 10;
9 modify (& num ) ;
10 printf ( " Value of num : % d \ n " , num ) ;
11 return 0;
12 }

Output:

Value of num: 50

5.1.4 Passing Arrays to Functions


Arrays are passed to functions by reference, as their name represents the address of the first element.

Syntax
return_type function_name(data_type array_name[], size_t size);

91
Example: Summing Elements of an Array

1 # include < stdio .h >


2
3 // Function to calculate sum of an array
4 int sumArray ( int arr [] , int size ) {
5 int sum = 0;
6 for ( int i = 0; i < size ; i ++) {
7 sum += arr [ i ];
8 }
9 return sum ;
10 }
11
12 int main () {
13 int numbers [] = {1 , 2 , 3 , 4 , 5};
14 int result = sumArray ( numbers , 5) ; // Passing array to function
15 printf ( " Sum : % d \ n " , result ) ;
16 return 0;
17 }

Output:
Sum: 15

Example: Modifying Array Elements

1 # include < stdio .h >


2
3 // Function to modify array elements
4 void doubleArray ( int arr [] , int size ) {
5 for ( int i = 0; i < size ; i ++) {
6 arr [ i ] *= 2;
7 }
8 }
9
10 int main () {
11 int numbers [] = {1 , 2 , 3 , 4 , 5};
12 doubleArray ( numbers , 5) ; // Passing array to function
13 for ( int i = 0; i < 5; i ++) {
14 printf ( " % d " , numbers [ i ]) ;
15 }
16 return 0;
17 }

Output:
2 4 6 8 10

Conclusion
- Functions are essential for organizing code into reusable components.
- Proper use of arguments and array passing ensures efficient handling of data.
- C functions support both pass-by-value and pass-by-reference techniques, making them versatile for various
use cases.

5.2 Scope and Lifetime:


In C programming, the **scope** of a variable defines where it can be accessed, while its **lifetime**
determines how long it stays in memory during program execution. Variables also have specific **storage
classes**, which define their scope, lifetime, and storage location.

92
5.2.1 Scope of Variables
The scope of a variable can be categorized as:
• Block Scope

• Function Scope
• File Scope

1) Block Scope
Variables declared inside a block (enclosed by curly braces {}) are accessible only within that block.

1 # include < stdio .h >


2
3 int main () {
4 int x = 10; // Block scope
5 if ( x > 5) {
6 int y = 20; // Block scope inside the ’ if ’ block
7 printf ( " x : %d , y : % d \ n " , x , y ) ;
8 }
9 // printf ( " y : % d \ n " , y ) ; // Error : y is out of scope
10 return 0;
11 }

Explanation: - x is accessible throughout main(). - y is only accessible inside the if block.

Output:
x: 10, y: 20

2) Function Scope
Labels used for goto statements have function scope. They can be accessed anywhere within the same
function.

1 # include < stdio .h >


2
3 int main () {
4 goto label ; // Jumps to the label
5 printf ( " This line is skipped .\ n " ) ;
6 label :
7 printf ( " Label reached .\ n " ) ;
8 return 0;
9 }

Output:
Label reached.

3) File Scope
Variables declared outside all functions are global variables and have file scope. They are accessible through-
out the file.

93
1 # include < stdio .h >
2
3 int globalVar = 10; // File scope
4
5 void display () {
6 printf ( " Global Variable : % d \ n " , globalVar ) ;
7 }
8
9 int main () {
10 display () ;
11 return 0;
12 }

Output:
Global Variable: 10

5.2.2 Lifetime of Variables and Storage Classes


The lifetime of a variable refers to how long it remains allocated in memory during program execution. C
provides four storage classes that determine a variable’s scope, lifetime, and visibility:
• auto (Automatic)
• static
• extern

• register

1) Automatic Storage Class (auto)


• Default for local variables.

• Scope: Block scope.


• Lifetime: Limited to the block in which it is declared.

1 # include < stdio .h >


2
3 int main () {
4 auto int x = 5; // Optional to specify ’ auto ’
5 printf ( " x : % d \ n " , x ) ;
6 return 0;
7 }

Output:
x: 5

2) Static Storage Class (static)


• Retains its value between function calls.
• Scope: Block or file.
• Lifetime: Entire program execution.

94
1 # include < stdio .h >
2
3 void counter () {
4 static int count = 0; // Retains its value
5 count ++;
6 printf ( " Count : % d \ n " , count ) ;
7 }
8
9 int main () {
10 counter () ;
11 counter () ;
12 counter () ;
13 return 0;
14 }

Output:
Count: 1
Count: 2
Count: 3

3) External Storage Class (extern)


• Allows global variables to be shared across multiple files.

• Scope: File scope (can be extended to other files).


• Lifetime: Entire program execution.

1 // File1 . c
2 # include < stdio .h >
3 extern int sharedVar ; // Declaration
4 void display () {
5 printf ( " Shared Variable : % d \ n " , sharedVar ) ;
6 }
7
8 // File2 . c
9 # include < stdio .h >
10 int sharedVar = 100; // Definition
11 int main () {
12 display () ;
13 return 0;
14 }

Output (when compiled together):


Shared Variable: 100

4) Register Storage Class (register)


• Suggests storing the variable in a CPU register for faster access.
• Scope: Block scope.

• Lifetime: Limited to the block in which it is declared.

95
1 # include < stdio .h >
2
3 int main () {
4 register int i ; // Stored in a register ( if possible )
5 for ( i = 0; i < 5; i ++) {
6 printf ( " % d " , i ) ;
7 }
8 return 0;
9 }

Output:

0 1 2 3 4

Summary of Storage Classes


Storage Class Scope Lifetime Default Initial Value Notes
auto Block Block Garbage value Default for local variables.
static Block or File Entire program Zero Retains value across calls.
extern File (or global) Entire program Zero Used to share across files.
register Block Block Garbage value Faster access (if possible).

96

You might also like