Programming in C
Programming in C
Unit-1
Each programming language contains a unique set of keywords and syntax, which are used
to create a set of instructions. Thousands of programming languages have been developed
till now, but each language has its specific purpose. These languages vary in the level of
abstraction they provide from the hardware. Some programming languages provide less or
no abstraction while some provide higher abstraction. Based on the levels of abstraction,
they can be classified into two categories:
Low-level language
High-level language
Low-level languages are typically used for system programming, device driver
development, and embedded systems.
High-level languages are Python, C++, C, C#, Visual Basic, and JavaScript. Low-level
languages are Machine language and Assembly language.
[Image 138.jpg]
The low-level language is a programming language that provides no abstraction from the
hardware, and it is represented in 0 or 1 forms, which are the machine instructions.
Creating a program in a machine-level language is a very difficult task as it is not easy for
the programmers to write the program in machine instructions. It is error-prone as it is not
easy to understand, and its maintenance is also very high.
A machine-level language is not portable as each computer has its machine instructions,
so if we write a program in one computer will no longer be valid in another computer.
The different processor architectures use different machine codes, for example, a PowerPC
processor contains RISC architecture, which requires different code than intel x86
processor, which has a CISC architecture.
Assembly Language
The assembly language contains some human-readable commands such as mov, add,
sub, etc. The problems which we were facing in machine-level language are reduced to
some extent by using an extended form of machine-level language known as assembly
language. Since assembly language instructions are written in English words like mov, add,
sub, so it is easier to write and understand.
The machine-level language comes at the lowest level in the hierarchy, so it has zero
abstraction level from the hardware. The assembly language comes above the machine
language means that it has less abstraction level from the hardware.
M/C language cannot be easily understood by humans while Assembly is easy to read,
write, and maintain. The machine-level language is written in binary digits, i.e., 0 and 1. The
assembly language is written in simple English language, so it is easily understandable by
the users.
It’does not require any translator as the machine code is directly executed by the
computer. In assembly language, the assembler is used to convert the assembly code into
machine code.
The high-level language is a programming language that allows a programmer to write the
programs which are independent of a particular type of computer. The high-level languages
are considered as high-level because they are closer to human languages than machine-
level languages.
The high-level language is easy to read, write, and maintain as it is written in English like
words.
The high-level languages are designed to overcome the limitation of low-level language,
i.e., portability. The high-level language is portable; i.e., these languages are machine-
independent.
The low-level language takes more time to execute.It executes at a faster pace.
It requires the assembler to convert the assembly code into machine code. It requires the
compiler to convert the high-level language instructions into machine code.
The machine code cannot run on all machines, so it is not a portable language. The high-
level code can run all the platforms, so it is a portable language.
Debugging and maintenance are not easier in a low-level language. Debugging and
maintenance are easier in a high-level ur language.
In the execution of the program, major role is played by two utility programs known as
Linker and Loader.
1. Linker: A linker is special program that combines the object files, generated by
compiler/assembler and other pieces of code to originate an executable file has .exe
extension. In the object file, linker searches and append all libraries needed for
execution of file. It regulates the memory space that will hold the code from each
module. It also merges two or more separate object programs and establishes link
among them.
1. Linkage Editor
2. Dynamic Linker
Symbol resolution: The linker resolves symbols in the program that are defined in one
module and referenced in another.
Code optimization: The linker optimizes the code generated by the compiler to reduce code
size and improve program performance.
Memory management: The linker assigns memory addresses to the code and data sections
of the program and resolves any conflicts that arise.
Library management: The linker can link external libraries into the executable file to provide
additional functionality.
[Image 139.jpg]
2. Loader: It is special program that takes input of executable files from linker, loads it to
main memory, and prepares this code for execution by computer. Loader allocates
memory space to program. Even it settles down symbolic reference between objects. It is
in charge of loading programs and libraries in operating system. The embedded computer
systems don’t have loaders. In them, code is executed through ROM. There are following
various loading schemes:
1. Absolute Loaders
2. Relocating Loaders
4. Bootstrap Loaders
Loading: The loader loads the executable file into memory and allocates memory for the
program.
Relocation: The loader adjusts the program’s memory addresses to reflect its location in
memory.
Symbol resolution: The loader resolves any unresolved external symbols that are required
by the program.
Dynamic linking: The loader can dynamically link libraries into the program at runtime to
provide additional functionality.
[Image 143.jpg]
[Image 141.jpg]
Example: Draw a flowchart to input two numbers from the user and display the largest of
two numbers.
[Image 142.jpg]
Syntax Error.
Run-Time Error.
Logical Error.
Semantic Error.
Linker Error.
1. Syntax errors:
These are the type of errors that occur when code violates the rules of the programming
language such as missing semicolons, brackets, or wrong indentation of the code,
2. Logical errors:
These are the type of errors that occurs when incorrect logic is implemented in the code
and the code produces unexpected output.
3. Runtime errors:
These are the errors caused by unexpected condition encountered while executing the
code that prevents the code to compile. These can be null pointer references, array out-o
1. Compiler :Compiler, as name suggests, is a process that is used to convert code into
machine instructions. It simply translates source code from high-level programming
language to low-level machine language. It is basically a complex software that performs
both code optimization and code generation. It also makes end code more efficient which
is optimized for execution time and memory space.
2. Debugger :Debugger, as name suggests, is a process used to remove bugs from code. It
simply allows testing and debugging other programs. Sometime, it also provides two
modes of operations i.e., full and partial simulation. It is used to prevent incorrect
operation of software or system. It also uses instruction-set simulators instead of running a
program directly on processor to achieve higher level of control over its execution.
Structure of C Programming
The basic structure of a C program is divided into 6 parts which makes it easy to read,
modify, document, and understand in a particular format. C program must follow the
below-mentioned outline in order to successfully compile and execute. Debugging is easier
in a well-structured C program.
There are 6 basic sections responsible for the proper execution of a program. Sections are
mentioned below:
Documentation
Preprocessor Section
Global Declaration
Main() Function
A character set is a collection of all characters (like letters, digits, symbols, etc.) that can
be used in code. It is classified into two main categories: the source character set and the
execution character set in C.
What is character type in C?
(Character data type allows its variable to store only a single character. The size of the
character is 1 byte. It is the most basic data type in C. It stores a single character and
requires a single byte of memory in almost all compilers. Range: (-128 to 127) or (0 to 255))
Keywords are predefined, reserved words used in programming that have special meanings
to the compiler. Keywords are part of the syntax and they cannot be used as an identifier.
QuestionA constant does not change its value as the equation is solved. A variable, on the
other hand, changes its value depending on the equation. Constants are usually written in
numbers(whether fractions, integers, decimals or real numbers). Variables are written as
letters or symbols.
Each variable in C has an associated data type. It specifies the type of data that the
variable can store like integer, character, floating, double, etc. Each data type requires
different amounts of memory and has some specific operations which can be performed
over it. The data type is a collection of data with values having fixed values, meaning as well
as its characteristics.
Data Types in C
Primitive Data Types Primitive data types are the most basic data types that are us.ed for
representing simple values such as integers, float, characters, etc.
User Defined Data Types The user-defined data types are defined by the user himself.
Derived Types The data types that are derived from the primitive or built-in datatypes are
referred to as Derived Data Types.
[Image 145.jpg]
Data Type
0 to 18,446,744,073,709,551,615 %llu
Format specifiers in C are used to take inputs and print the output of a type. The symbol we
use in every format specifier is %. Format specifiers tell the compiler about the type of data
that must be given or input and the type of data that must be printed on the screen.
The three categories of operators based on the number of operands they require are: Unary
operators: which require one operand (Un) Binary operators: which require two operands
(Bi) Ternary operators: which require three operands (Ter)
Expressions with operators also include assignment expressions, which use unary or
binary assignment operators. The unary assignment operators are the increment ( ++ ) and
decrement ( -- ) operators; the binary assignment operators are the simple-assignment
operator ( = ) and the compound-assignment operators.
Unary Operators in C
Unary operators in C are operators that operate on a single operand. They are used to
perform various operations, such as incrementing/decrementing a value, negating an
expression, or dereferencing a pointer. Here are the most commonly used unary operators
in C:
Increment (++): Increases the value of its operand by 1. It can be used in two forms:
Prefix (++x): Increments the value of x and then returns the new value.
Prefix (–x): Decrements the value of x and then returns the new value.
Logical NOT (!): Inverts the boolean value of its operand. If the operand is non-zero, it
returns 0 (false), and if the operand is zero, it returns 1 (true).
Bitwise NOT (~): Performs a bitwise negation on its operand, inverting each bit.
Dereference (*): Accesses the value at the address pointed to by its operand (the opposite
of the address-of operator).
These unary operators are widely used in C programming for various purposes, including
memory management, arithmetic operations, and logical operations.
Operators are used in programs to manipulate data and variables. They can be categorized
into unary, binary, and ternary operators based on the number of operands they take.
Unary Operators in C
Unary operators in C are operators that operate on a single operand. They are used to
perform various operations, such as incrementing/decrementing a value, negating an
expression, or dereferencing a pointer. Here are the most commonly used unary operators
in C:
Increment (++): Increases the value of its operand by 1. It can be used in two forms:
Prefix (++x): Increments the value of x and then returns the new value.
Decrement (–): Decreases the value of its operand by 1. Similar to increment, it also has
two forms:
Prefix (–x): Decrements the value of x and then returns the new value.
Bitwise NOT (~): Performs a bitwise negation on its operand, inverting each bit.
Dereference (*): Accesses the value at the address pointed to by its operand (the opposite
of the address-of operator).
These unary operators are widely used in C programming for various purposes, including
memory management, arithmetic operations, and logical operations.
Binary Operators in C
In the C programming language, binary operators are used to perform operations on two
operands. Here are the most commonly used binary operators in C:
Arithmetic Operators:
Subtraction (-): Subtracts the second operand from the first. E.g., a – b.
Relational Operators:
Equal to (==): Checks if two operands are equal. Returns true if they are. E.g., a == b.
Not equal to (!=): Checks if two operands are not equal. E.g., a != b.
Greater than (>): Checks if the left operand is greater than the right operand. E.g., a > b.
Less than (<): Checks if the left operand is less than the right operand. E.g., a < b.
Greater than or equal to (>=): Checks if the left operand is greater than or equal to the right
operand. E.g., a >= b.
Less than or equal to (<=): Checks if the left operand is less than or equal to the right
operand. E.g., a <= b.
Logical Operators:
Logical AND (&&): Returns true if both operands are true. E.g., a && b.
Logical NOT (!): Used to reverse the logical state of its operand. E.g., !a.
Bitwise Operators:
Bitwise AND (&): Performs a bitwise AND on two integers. E.g., a & b.
Bitwise left shift (<<): Shifts the bits of the first operand to the left by the number of
positions specified by the second operand. E.g., a << 2.
Bitwise right shift (>>): Shifts the bits of the first operand to the right by the number of
positions specified by the second operand. E.g., a >> 2.
Assignment Operators:
Simple assignment (=): Assigns the value of the right operand to the left operand. E.g., a =
b.
Add and assign (+=): Adds the right operand to the left operand and assigns the result to the
left operand. E.g., a += b.
Subtract and assign (-=): Subtracts the right operand from the left operand and assigns the
result to the left operand. E.g., a -= b.
Multiply and assign (*=): Multiply the right operand with the left operand and assign the
result to the left operand. E.g., a *= b.
Divide and assign (/=): Divides the left operand by the right operand and assigns the result
to the left operand. E.g., a /= b.
Modulus and assign (%=): Applies modulus operation and assigns the result to the left
operand. E.g., a %= b.
Ternary Operators in C
Ternary operators in C are a shorthand way of writing conditional statements. They are a
compact form of the if-else statement and are often used for simple conditional
assignments. The syntax of the ternary operator in C is:
For example:
Int a = 5, b = 10;
Int max;
Max = (a > b) ? a : b;
In this example, the ternary operator checks if a is greater than b. If true, max is assigned
the value of a; otherwise, it is assigned the value of b.
Operator precedence determines the grouping of terms in an expression and decides how
an expression is evaluated. Certain operators have higher precedence than others; for
example, the multiplication operator has a higher precedence than the addition operator.
For example, x = 7 + 3 * 2; here, x is assigned 13, not 20 because operator * has a higher
precedence than +, so it first gets multiplied with 3*2 and then adds into 7.
Here, operators with the highest precedence appear at the top of the table, those with the
lowest appear at the bottom. Within an expression, higher precedence operators will be
evaluated first.
Assignment = += -= *= /=