C Programming With Linux I
C Programming With Linux I
Lecture Review
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
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:
Example2:
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.
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
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
7
Start
Input A
Input B
A > B?
no
yes
MAX = A MAX = B
Output MAX
End
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.
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.
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.
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.
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.
11
3. Platform-Specific Syntax: Unix/Linux systems use forward slashes (/) to separate directories, while
Windows systems use backslashes (\).
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.
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.
Output:
1 Desktop Documents Downloads Music Pictures Videos
Options:
• ls -l: List in long format (shows file permissions, owner, size, and date).
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
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
Key Points:
• Absolute paths always start with / (the root directory).
• They are independent of your current location in the file system.
Syntax:
Examples:
1. Assume your current working directory is /home/john. To navigate to the Documents directory inside
john’s home directory:
1 cd 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.
Output:
1 This is the content of the file .
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
This opens gedit with a blank editor where you can write and save your content.
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.
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.
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
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.
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.
—
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
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.
Options:
• rm -r: Remove directories and their contents recursively.
Example:
1 rm -r new_folder
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
Output:
1 2: hello world
2 5: Hello again
3 8: HELLO there
Here, grep shows the line numbers where the pattern ”hello” appears.
—
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.
—
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.”
—
20
Summary of Common grep Options
• -i: Perform a case-insensitive search.
• -n: Show line numbers with the matching lines.
This command will return all lines in the file filename that begin with the word ”start”.
This command will return all lines in the file filename that end with the word ”end”.
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
21
Output:
apple
apple pie
Output:
apple pie
pie apple
Output:
apple
By using these options, grep becomes a powerful and versatile tool for searching text files and filtering data
in Linux.
• 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.
—
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 - -
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.
—
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
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
• 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
Output
27
3. Set read-only permission for others:
1 chmod o = r file . txt
Output
Output
Example Output:
1 - rwxr - xr - - 1 user group 1234 Nov 25 12:00 file . txt
28
• rwx: Owner permissions (read, write, execute).
• r-x: Group permissions (read, execute).
• r--: Permissions for others (read-only).
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.
—
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.
• -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.
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.
This launches the top interface, which updates in real-time. To exit top, press q.
—
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
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.
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% /
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 }
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:
• 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
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.
• 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:
• 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.
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.
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.
• 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).
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,
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.
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
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
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 .
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
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
• 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
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
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.
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).
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:
Hence:
−54 = 11001010 (Two’s Complement)
48
Table for Two’s Complement:
• 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:
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.
• 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.
#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:
50
ASCII Table (Selected Characters)
Below is a small subset of the ASCII table:
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:
13.62510 = 1101.1012
11012 = 1 × 23 + 1 × 22 + 0 × 21 + 1 × 20 = 8 + 4 + 0 + 1 = 13
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
101102 = 1 × 24 + 0 × 23 + 1 × 22 + 1 × 21 + 0 × 20 = 16 + 0 + 4 + 2 + 0 = 22
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
Final Result:
110.10112 = 6.687510
2. Biasing: The bias for single precision is 127. The biased exponent is:
2 + 127 = 129
0 10000001 01110000000000000000000
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
4. Decimal Value:
5.75
55
Example 5: Convert IEEE 754 Hexadecimal 0xC0800000 to Decimal
1. Binary Representation: Convert 0xC0800000 to binary:
4. Decimal Value:
−3.25
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:
• 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:
• 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.
Example:
#include <stdio.h>
int main() {
// This is a single-line comment
printf("Hello, World!\n"); /* This is a multi-line comment */
return 0;
}
59
Examples of Invalid Identifiers
• 123number (cannot start with a digit),
• int (C keyword),
c. Keywords
Keywords are reserved words in C, each with a predefined meaning. Examples include int, return, for,
while, and if.
Example:
Table 8: C Keywords
• 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.
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.
• 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).
d. Constants
Constants are fixed values that do not change during program execution. They can be:
• Integer constants: Whole numbers (e.g., 10, -42).
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
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.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
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
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
• Arithmetic Operators: +, -, *, /, %.
• Relational 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
• == : Equal to.
• != : Not equal to.
Example:
int a = 10, b = 20;
bool result1 = (a == b); // result1 = false
bool result2 = (a < b); // result2 = true
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.
Example:
int a = 5, b = 2, c = 3;
int result = a + b * c; // result = 5 + (2 * 3) = 11 (multiplication has higher precedence)
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
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.
#include <stdio.h>
int main() {
int a, b;
a = 10; // Assigning 10 to a
b = a; // Assigning value of a to b
a = 10, b = 10
70
#include <stdio.h>
int main() {
int num = 5;
num++; // Increment operator
printf("num = %d\n", num);
return 0;
}
Output:
num = 6
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
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
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
#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
int main() {
int num = 10;
printf("Size of int: %lu bytes\n", sizeof(num));
return 0;
}
Output:
Size of int: 4 bytes
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
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.
Algorithm
1. Set the initial value of the control variable.
75
Flowchart
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 -
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;
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.
Flowchart
#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 -
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;
79
fact = fact * num;
num--;
}
return 0;
}
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 -
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;
}
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.
Syntax
data_type array_name[size] = {value1, value2, ..., valueN};
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.
#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.
Syntax
data_type array_name[rows][columns] = {
{value1, value2, ...},
{value3, value4, ...},
...
};
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...
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.
Example Calculation
If Base Address = 1000, the address of matrix[1][2] is:
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.
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}
};
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
85
int main() {
int rows, cols, i, j;
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
int main() {
int rows1, cols1, rows2, cols2, i, j, k;
if (cols1 != rows2) {
printf("Matrix multiplication not possible.\n");
return 1;
}
// 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
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
89
}
int main() {
int num1, num2, sum;
return 0;
}
Sample Output
Enter the base and exponent: 2 3
2 raised to the power of 3 is: 8
Syntax
return_type function_name(parameter_list);
Output:
Product: 12
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.
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.
Output:
Value of num: 50
Syntax
return_type function_name(data_type array_name[], size_t size);
91
Example: Summing Elements of an Array
Output:
Sum: 15
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.
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.
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.
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
• register
Output:
x: 5
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
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 }
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
96