C Course Material
C Course Material
C-Course
Material
Contents
1. Introduction
About C Language.
About Microcontrollers
RISC Processors
CISC Processors
2. Variables & Operators
3. Control Structures
a. IF statement
i. Ladder IF statement
b. FOR statement
c. WHILE statement
d. DO-WHILE statement
e. SWITCH statement
Examples
4. Functions, User define Functions & Macros
5. Derivative Data types
a. Arrays
b. Structure
c. Union
d. Enumerators
e. Tree
f. Linked List
g. Pointers
Examples
1. Introduction:
Powerful features, simple syntax, and portability make C a preferred language among
programmers for business and industrial applications. Portability means that C programs written
for a computer with a particular kind of processor say Intel can be executed on computers with
different processors such as Motorola, Sun Sparc, or IBM with little or no modification.
1.1.
HISTORY OF C:
In the early days of computers, the only programming languages available to programmers
were two low level languages, machine and assembly language. Programming in machine and
assembly languages was tedious and time consuming because all memory, stack, interrupts and
hardware is to be managed by programmer. Increase in use of computers, many high-level
languages such as FORTRAN, Basic and Pascal are developed.
By using high-level languages hardware will be simple, syntax made easier. In 1972, the
Unix Operating system was being developed. During this time, the concept of a System
programming language having attributes of both low level and high level languages also
developed. Brian W. Kernighan and Dennis M. Ritchie developed C at Bell Laboratories as a
system programming language. Their goal was to develop a language that was simple and flexible
enough to be used in a variety of different platforms. In 1983, the American National Standards
Institute formed a committee to produce a C programming language standard. This "ANSI C" was
completed in 1988. C with objects) is the most popular programming language in the world and is
the dominant in Microsoft Windows application development. Small C can be used in
microcontrollers.
1.2.
CHARACTERISTICS OF C:
Modularity
Portability
Extendibility
Speed
Flexibility
Modularity:
Ability to breakdown a large module into manageable sub modules called as modularity,
which is an important feature of structured programming languages.
Advantages:
1. Projects can be completed in time.
2. Debugging will be easier and faster.
Portability:
The ability to port i.e. to install the software in different platform is called portability.
Highest degree of portability: C language offers highest degree of portability i.e., percentage of
changes to be made to the sources code is at minimum when the software is to be loaded in
another platform. Percentage of changes to the source code is minimum. The software that is
100% portable is also called as platform independent software or architecture neutral software.
Eg: Java.
Extendibility:
Ability to extend the existing software by adding new features is called as extendibility.
Speed:
C is also called as middle level language because programs written in c language run at
the speeds matching to that of the same programs written in assembly language so c language
has both the merits of high level and middle level language and because if this feature it is mainly
used in developing system software.
Flexibility:
C language has right number of reverse words which allows the programmers to have
complete control on the language.
1.3.
1.4.
C VS ASSEMBLY:
C
Writing Programs much faster
Learning and mastering takes less time
Portable
Well defined structured
Powerful keywords
Supports modularity
High-level language
1.5.
ASSEMBLY
Writing programs are slower
It takes more time
Non portable
Not a well defined structured
More number of keywords
Does not support modularity
Low-level language
o
o
o
o
C is simple.
There are only 32 keywords so C is very easy to master.
C programs run faster than programs written in most other languages.
C enables easy communication with computer hardware making it easy to
write system
1.6.
C is one of the most commonly used software languages used on embedded device
controllers. One reason is because it is one of the few software languages that operates on both 8
bit controllers and 64 bit PCs, meaning that many computer programmers can write C software
for both personal computers and embedded devices. The C language can also use very simple
commands to control the device, freeing up the limited memory of the device to hold many
commands or parameters. C can be written for both microcontrollers and digital signal processors.
Code is written in C on a programmer's PC. Code is run through a compiler on the
programmer's PC to create a software program. The embedded system software may be run
through a simulator on the programmer's computer. The software program is copied onto the
controller using a "programmer." The controller is then tested on a "test bed" to ensure that it
works properly.
1.7.
Bluetooth devices are programmed in C. PIC microcontrollers such as those used in web
cameras are frequently programmed in C. PIC microcontrollers programmed in C have also been
used in LED (light emitting diodes) devices and LCD (liquid crystal display) monitors. USB
devices are embedded devices frequently coded in C.
1.8.
The American National Standards Institute (ANSI) has written standards for the C
programming language. The International Standards Organization wrote standard ISO/IEC 9899
for the C programming language. The Motor Industry Software Reliability Association has
created a proprietary set of standards for programming in C for embedded devices in automobile.
1.9.
WHERE IS C USEFUL?
Cs ability to communicate directly with hardware makes it a powerful choice for system
programmers. In fact, popular operating systems such as Unix and Linux are written entirely in C.
Additionally, even compilers and interpreters for other languages such as FORTRAN, PASCAL,
and BASIC are written in C. However, Cs scope is not just limited to developing system
programs. It is also used to develop any kind of application, including complex business ones.
The following is a partial list of areas where C language is used:
Embedded Systems
Systems Programming
Artificial Intelligence
Industrial Automation
Computer Graphics
Space Research
Image Processing
Game Programming
1.10. C-COMPILERS:
When you write any program in C language then to run that program you need to compile
that program using a C Compiler which converts your program into a language understandable by
a computer. This is called machine language (i.e. binary format). So before proceeding, make sure
you have C Compiler available at your computer.
The next phase is to link the object files to produce an executable. During linking, the
static linker (ld) sees the unresolved reference to printf() and searches the available libraries for an
implementation for printf(). In general this will be found in the C library (libC on Solaris). Now,
the linker has two options:
It (linker) can take the printf() implementation from the library and copy it into the final
executable. The linker then searches the printf() implemenation for other unresolved references,
and again consult the libraries for resolution. This process will be performed iteratively until all
references to the symbols were resolved. This is known as static linking
If the C library is realized as a `shared library', the linker can simply put a reference to the
C library into the final executable. Still the linker performs symbol resolution checking as above,
to determine if the reference to the printf() function necessiates further references to other (shared
or nonshared) libraries. This is known as dynamic linking
4) Run the executable
What happens when you run the executable, depends on whether it was linked statically
or dynamically:
A statically linked executable is self contained. It is loaded into memory. The entry
point, whose designation is system dependent (for eg, the `__main' symbol) is found and called.
This entry function, usually provided by the compiler or a library, performs some setup and
initialization and then calls the user-defined main() function and the instructions inside main()
function gets executed
In a dynamically linked executable, after loading the executable binary into memory, the
dynamic linker (ld.so.1) takes control first. It reads the library references to dynamic libraries
produced by the static linker, and loads them into memory. It then performs symbol resolution
again and updates all references to symbols in the shared library to point to their actual location,
which can only be determined at runtime, because the shared libraries might be loaded to different
memory locations each time the executable binary gets executed
ALL
User friendly
Machine independent
Has comparably less statement than assembly language
Portable
Full optimization cannot be achieved
Less time to code
Easy to debug
Faster approach
Operates directly on the register
More statement
Not portable
Machine dependent
MLL
Not portable
Machine dependent
About Microcontrollers:
Endian is the ordering of bytes in scalar data on the machine.
Big Endean:
It stores scalars in their natural order, with most significant byte in the lowest numeric byte
address. Examples of big endian processors are the IBM System 360 and 370, Motorola 680x0 and most
RISC processors.
Little Endean:
It stores scalars with the least significant byte in the lowest numeric byte address. Examples of
little endian processors are the Digital VAX and Intel x86 (including Pentium).
Reduced Instruction Set Computers (RISC) have a small, compact instruction set. In most
business applications and in programs created by compilers from high level language source,
RISC processors usually perform the most work in the shortest time.
Eg: IBM RS6000, MC88100, DECs Alpha 21064, 21164 and 21264 processors
* 5 or 6 interrupts
* 2 or 3 16-bit timer/counters
* Programmable full-duplex serial port
* 32 I/O lines (four 8-bit ports)
* RAM
* ROM/EPROM in some models
Interrupts
One strong point of the 8051 is the way it handles interrupts. Vectoring to fixed 8-byte
areas is convenient and efficient. Most interrupt routines are very short (or at least they should
be), and generally can fit into the 8-byte area. Of course if your interrupt routine is longer, you
can still jump to the appropriate routine from within the 8 byte interrupt region.
The 8051 instruction set is optimized for the one-bit operations so often desired in realworld, real-time control applications. The boolean processor provides direct support for bit
manipulation. This leads to more efficient programs that need to deal with binary input and output
conditions inherent in digital-control problems. Bit addressing can be used for test pin monitoring
or program control flags.
The 8051 micro-controller architecture
This figures shows the main features and components that the designer can interact with.
You can notice that the 89S52 has four different ports, each one having eight Input/output lines
providing a total of 32 I/O lines. Those ports can be used to output DATA and orders do other
devices, or to read the state of a sensor, or a switch. Most of the ports of the 89S52 have dual
function meaning that they can be used for two different functions: the fist one is to perform
input/output operations and the second one is used to implement special features of the
microcontroller like counting external pulses, interrupting the execution of the program according
to external events, performing serial data transfer or connecting the chip to a computer to update
the software.
Special Function Registers (SFRs)
The 8051 is a flexible microcontroller with a relatively large number of modes of
operations. The program inspects and changes the operating mode of the 8051 by manipulating
the values of the 8051's Special Function Registers (SFRs).
SFRs are accessed as if they were normal Internal RAM. The only difference is that
Internal RAM is from address 00h through 7Fh whereas SFR registers exist in the address range
of 80h through FFh.Each SFR has an address (80h through FFh) and a name. The following chart
provides a graphical presentation of the 8051's SFRs, their names, and their address.
locations (00H to 7FH) of internal RAM are used by the programmer for storing data while the
second 128 locations (80H to FFH) are the Special Function Registers (SFRs)
Introduction to PIC16Fxx :
Microchip manufacture a series of microcontrollers called PIC (Peripheral Interface
Conroller). There are many different flavours available, some basic low memory types, going
right up through to ones that have Analogue - To- Digital converters and even PWM built in.
There are several ways of programming the PIC - using BASIC, C, or Assembly
Language.
The PIC architecture is characterized by its multiple attributes:
Separate code and data spaces (Harvard architecture) for devices other than PIC32, which
in the opcode)
All RAM locations function as registers as both source and/or destination of math and other
functions.[3]
A hardware stack for storing return addresses
A fairly small amount of addressable data space (typically 256 bytes), extended through
banking
Data space mapped CPU, port, and peripheral registers
The program counter is also mapped into the data space and writable
Memory Arrangement
There are two memory blocks in the PIC16F8X:
Each block has its own bus, so that access to each block can occur during the same clock cycle.
The data memory can further be broken down into:
Peripherals
CHAPTER 2
STRUCTURE OF C PROGRAM ,
DATA
2.1.
STRUCTURE OF C PROGRAM:
The structure of a C program is a protocol (rules) to the programmer, while writing a C
program. The general basic structure of C program is shown in the figure below. The whole
program is controlled within main ( ) along with left brace denoted by { and right braces
denoted by }. If you need to declare local variables and executable program structures are
enclosed within { and } is called the body of the main function. The main ( ) function can be
preceded by documentation, preprocessor statements and global declarations.
2.1.1. DOCUMENTATIONS:
The documentation section consist of a set of comment lines giving the name of the
program, another name and other details, which the programmer would like to use later.
The preprocessor statements begin with # symbol and are also called the preprocessor
directive. These statements instruct the compiler to include C preprocessors such as header files
and symbolic constants before compiling the C program. Some of the preprocessor statements are
listed below.
2.1.5 BRACES:
Every C program should have a pair of curly braces ({, }). The left braces indicates the
beginning of the main ( ) function and the right braces indicates the end of the main ( ) function.
These braces can also be used to indicate the user-defined functions beginning and ending. These
two braces can also be used in compound statements.
2.2. DATATYPES IN C:
C language is rich in its data types. ANSI C supports four classes of data types:
Integer (int)
Character (char)
Floating point (float)
Double-precision floating point (double).
Various data types and terminology used to describe is given below diagram.
Integer type:
Signed type
Int
Short int
Long int
Unsigned type
Unsigned int
Unsigned short int
Unsigned long int
Character type:
Signed char
Unsigned char
Floating Type
Float
Double
Long double
Range
-128 to 127
-32,768 to 32,767
3.4e-38 to 3.4e+38
1.7e-308 to 1.7e+308
Integer types:
Integers are whole numbers with a range of values supported by a particular machine. Size
of an integer that can be stored depends on the computer. If we use a 16-bit word length, the size
of the integer value is limited to the range of (-2 n-1 to +2n-1-1). A signed bit uses one bit for sign
and 15 bits for the magnitude of the number. C has different forms of integer storage like short
int, long int, in both signed and unsigned forms.
Floating point types:
Floating point numbers are stored in all machines, with 6 digits of precision. This data
type is defined by using keyword float. When the accuracy provided by float number is not
sufficient, the type double can be used. The data type double can have precision of 14 digits.
Further extension in precision we can use long double.
Character types:
A single character can be defined as a character (char) type data. Characters are usually
stored in 8 bits (one byte) of internal storage. While unsigned char have values between 0 to 255,
signed char have values from -128 to 127.
SI.No Keyword
Range
Storage in
1.
2.
3.
4.
5.
6.
7.
Char (signed)
Unsigned char
Int
Unsigned int
Short
Unsigned short
Long
-127 to 127
0 to 255
-32,768 to 32,767
0 to 65,535
-32,768 to 32,767
0 to 65,535
-2,147,483,648 to
Bytes
1
1
2
2
2
2
4
8.
9.
Unsigned long
Float
2,147,483,647
0 to 4,294,967,295
1.2E-38 to 3.4E38, approx.
4
4
10.
Double
Derived data type is constructed from basic data type. Example: Arrays, Structures, Enumerated
data types, Union etc..(discussed in the later part of the material)
There are four storage classes which can be used in a C Program. They are auto, register,
static and extern.
The auto storage-class specifier declares an automatic variable, a variable with a local lifetime. An
An internal static variable (a static variable with local or block scope) can be initialized
with the address of any external or static item, but not with the address of another auto
item, because the address of an auto item is not a constant.
Keyword : auto
Storage Location : Main memory
Initial Value : Garbage Value
Life : Control remains in a block where it is defined.
Scope : Local to the block in which variable is declared.
Syntax:
auto [data_type] [variable_name];
ex: auto int var; or int var;
Registers are memory located within the CPU itself where data can be stored and accessed
quickly. Normally, the compiler determines what data is to be stored in the registers of the
CPU and at what instant.
The C language provides the storage class register so that the programmer can suggest to
the compiler that particular automatic variables should be allocated to CPU registers, if
possible and it is not an obligation for the CPU to do this.
The register variables provide a certain control over efficiency of program execution.
Variables which are used repeatedly or whose access times are critical may be declared to
be of storage class register.
It is not applicable for arrays, structures or pointers and it cannot not be used with static or
external storage class.
Keyword : register
Storage Location : CPU Register
Initial Value : Garbage
Life : Local to the block in which variable is declared.
Scope : Local to the block.
Syntax:
register [data_type] [variable_name];
ex: register int var;
static storage class provides a lifetime over the entire program, however; it provides a way
to limit the scope of such variables, and static storage class is declared with the keyword
static as the class specifier when the variable is defined.
Static automatic variables continue to exist even after the block in which they are defined
terminates. Thus, the value of a static variable in a function is retained between repeated
function calls to the same function.
The scope of static automatic variables is identical to that of automatic variables, i.e. it is
local to the block in which it is defined.
Static variables may be initialized in their declarations; however, the initializers must be
constant expressions, and initialization is done only once at compile time when memory
is allocated for the static variable.
static variables are automatically initialized to zero upon memory allocation just as
external variables are. Static storage class can be specified for automatic as well as
external variables such as:
static extern var;
Static storage class can be used only if we want the value of a variable to persist between
different function calls.
o
o
o
o
o
Keyword : static
Storage Location : Main memory
Initial Value : Zero and can be initialize once only.
Life : depends on function calls and the whole application or program.
Scope : Local to the block.
Syntax:
static [data_type] [variable_name];
ex: static int var;
All variables we have seen so far have had limited scope (the block in which they are
declared) and limited lifetimes (as for automatic variables).
However, in some applications it may be useful to have data which is accessible from
within any block and/or which remains in existence for the entire execution of the
program. Such variables are called global variables, and the C language provides storage
classes which can meet these requirements; namely, the external (extern) and static
(static) classes.
External variables may be declared outside any function block in a source code file the
same way any other variable is declared; by specifying its type and name (extern keyword
may be omitted).
Typically if declared and defined at the beginning of a source file, the extern keyword can
be omitted. If the program is in several source files, and a variable is defined in let say
file1.c and used in file2.c and file3.c then the extern keyword must be used in file2.c and
file3.c.
But, usual practice is to collect extern declarations of variables and functions in a separate
header file (.h file) then included by using #include directive.
Memory for such variables is allocated when the program begins execution, and remains
allocated until the program terminates. For most C implementations, every byte of
memory allocated for an external variable is initialized to zero.
The scope of external variables is global, i.e. the entire source code in the file following
the declarations. All functions following the declaration may access the external variable
by using its name. However, if a local variable having the same name is declared within a
function, references to the name will access the local variable cell.
o
Keyword : extern
would not be required to represent the value 150. Instead the value 150 could easily be saved in
an integer of 1 Byte in size, but the default size of an integer is 2 Bytes. So we have a problem
here. Well, note that we cant solve.
To override the default nature of a data type, C has provided us with data type modifiers as
follows:
Signed:
By default all data types are declared as signed. Signed means that the data type is capable of
storing negative values.
Unsigned:
To modify a data types behavior so that it can only store positive values, we require to use the
data type unsigned. For example, if we were to declare a variable age, we know that an age cannot
be represented by negative values and hence, we can modify the default behavior of the int data
type as follows:
unsigned int age;
This declaration allows the age variable to store only positive values. An immediate effect is that
the range changes from (-32768 to 32767) to (0 to 65536)
Long:
Many times in our programs we would want to store values beyond the storage capacity of the
basic data types. In such cases we use the data type modifier long. This doubles the storage
capacity of the data type being used.
E.g. long int annual salary will make the storage capacity of variable annual salary to 4 bytes. The
exception to this is long double, which modifies the size of the double data type to 10 bytes.
Please note that in some compilers this has no effect.
Short:
If long data type modifier doubles the size, short on the other hand reduces the size of the data
type to half. Please refer to the example of age variable to explain the concept of data type
modifiers. The same will be achieved by providing the declaration of age as follows:
short int age;
This declaration above, will provide the variable age with only 1 byte and its data range will be
from -128 to 127.
For instance
main()
{
float a;
a = (float) 5 / 3;
}
The above program gives result as 1.666666. This is because the integer 5 is converted to floating
point value before division and the operation between float and integer results in float.
From the above it is clear that the usage of typecasting is to make a variable of one type,
act like another type for one single operation. So by using this ability of typecasting it is possible
for create ASCII characters by typecasting integer to its character equivalent.
Typecasting is also used in arithmetic operation to get correct result. This is very much
needed in case of division when integer gets divided and the remainder is omitted. In order to get
correct precision value, one can make use of typecast as shown in example above. Another use of
the typecasting is shown in example below.
For instance:
main()
{
int a = 5000, b = 7000 ;
long int c = a * b ;
}
Here two integers are multiplied and the result is truncated and stored in variable c of type long
int. But this would not fetch correct result for all. To get a more desired output the code is written
as
long int c = (long int) a * b;
Though typecast has so many uses one must take care about its usage since using typecast in
wrong places may cause loss of data like for instance truncating a float when typecasting to an int.
#include <stdio.h>
main()
{
double d1 = 1234.56;
int i1=456;
Output:
The value of d1 as int without cast operator 1889785610
The value of d1 as int with cast operator 1234
The value of i1 as double without cast operator 1234.559570
The value of i1 as double with cast operator 456.000000
Effect of multiple unary operator 11.000000
Effect of multiple unary operator -11.000000
Effect of multiple unary operator 10.000000
Effect of multiple unary operator -10.000000
can
be
avoided
with
an
explicit
conversion.
short a=2000;
int b;
b = (int) a;
b = int (a);
// functional notation
will be double.
Else, if one of the operands is float, the other will be converted to float and the result will
be float.
Else if one of the operand is unsigned long int, the other will be converted to unsigned
long int and the result will be unsigned long int.
C automatically converts all floating point operands to double precision. The final result of an
expression is converted to the type of the variable on the left of the assignment sign before
assigning the value to it. However, the following changes are introduced during the final
assignment:
CHAPTER 3
OPERATORS IN C
3.1. OPERATOR
An operator is a symbol that tells the computer to perform certain mathematical or logical
manipulations. C supports a rich set of operators. Operators are used in programs to manipulate data and
variables. They usually form a part of the mathematical of logical expressions.
Arithmetic
Relational
Logical
Increment or Decrement
Conditional
Bitwise
Assignment
Special
3.1.1.
ARITHMETIC OPERATORS:
C provides all the basic operators. The operators +, -, *, and / all work the same way as they do in
other languages. These can operate on any built-in data type allowed in C. The unary minus operator, in
effect, multiplies its single operand by -1.
Operator
Meaning
Multiplication
Division
Modulo Division
Integer division truncates any fractional part. The modulo division produces the remainder of an
integer division. Examples of arithmetic operators are:
ab
a+b
a*b
a/b
Here a and b are called operands. The modulo division operator % cannot be used on floating point data. C
does not have an operator for exponentiation.
Integer Arithmetic: When both the operands in a single arithmetic expression such as a + b are integers,
the expression is called as integer expression, and the operation is called integer arithmetic. Integer
arithmetic always yields an integer value. The largest integer depends on the machine. During integer
division, if both the operands are of same sign, the result is truncated towards zero, if one of them is
negative; the direction of truncation is implementation dependent. That is,
6/7 = 0 and -6/-7 = 0
But -6/7 may be zero or -1(machine dependent)
Similarly during modulo division, the sign of the result is always the sign of the first operand (the
dividend) this is
-14 % 3 = 2
-14 % -3 = -2
14 % -3 = 2
Real Arithmetic: An arithmetic operation involving only real operands is called real arithmetic. Any
operand may have either in decimal or exponential notation. Since floating point values are rounded to the
number of significant digits permissible, the final value is an approximation of the correct result.
If x, y and z are floats, then we will have:
X = 6.0/7.0 = 0.857143
Y = 1.0/3.0 = 0.333333
The operator % cannot be used with real operands.
Mixed_Mode Arithmetic: When one of the operand is real and the other is integer, the expression is
called mixed-mode arithmetic expression. If either operand is of the real type, then only the real expression
is performed and the result is always a real number. Thus
15/10 = 1.5
Where as
15/10 = 1
If the numerator term is less then the denominator term (b<a), then the following rules are applied.
1. b % a
gives b
2. (-b) % a
gives (-b)
gives (-a)
If the division has both the numerator and denominator are real values then the result is also real. If it is
mixed that means one is 'int' and second is in 'float' then also the result is 'real'.
The +,-,*,and % are divided into two types.
They are,
1. low priority group and
2. high priority group
The low priority group is + and -.
The high priority group is * and /.
3.1.2.
RELATIONAL OPEARTOR:
We often compare two quantities, and depending on their relation, take certain decisions. For
example, we may compare the age of two persons, or the price of two items, and so on. These comparisons
can be done with the help of relational operators. Any expression which contains relational operators is
called relational expressions. The value of relational expression is either one or zero. If the specified
relation is true then result is one. If the specified relation is false then result is zero. C supports six
relational operators in all.
operator
Meaning
<
is less than
<=
>
is greater than
>=
==
is equal to
!=
is not equal to
A simple relational expression contains only one relational operator takes the following form:
Arithmetic exp-1
relational operator
Arithmetic exp-2
5.8 >=
TRUE
<=
TRUE
-90 >=
FALSE
TRUE
!=
When arithmetic expressions are used on either side of a relational operator, the arithmetic expressions will
be evaluated first and then the results compared. That is, arithmetic operators have a higher priority over
relational operators. Relational operators are used in decision statements such as, if and while to decide the
course of action of a running program.
3.1.3.
LOGICAL OPERATORS:
Meaning
&&
Logical AND
||
Logical OR
Logical NOT
Truth table
op-1
op-2
op-1 || op-2
non-zero
non-zero
non-zero
non-zero
3.1.4.
ASSIGNMENT OPERATORS:
Assignment operators are used to assign the result of an expression of a variable. In C has a set of
shorthand assignment operators of the form
v op = exp;
Where v is the variable, exp is an expression and op is a C binary arithmetic operator. The operator = is
known as the shorthand assignment operator.
the assignment statement
v op = exp;
v = v op(exp);
Is equivalent to
Consider an example
This is same as the statement
x += y+1;
x = x+(y+1). The shorthand operator += means add y+1 to x or
increment x by y+1.
Table: Shorthand assignment operators
a=a+1
a += 1
a = a -1
a -= 1
a = a * (n +1)
a *= n+1
a = a/ (n+1)
a /= n+1
a = a %b
a %=b
What appears on the left-hand side need not be replaced and therefore if becomes easier to write
3.1.5.
The operator ++ adds 1 to the operand while -- subtracts 1. Both are unary operators takes the following
form:
++m; or m++;
--m; or m--;
++m; is equivalent to m = m+1;(or m+=1;)
--m; is equivalent to m = m-1; (or m-=1;)
We use increment and decrement statements in for and while loops extensively.
While ++m and m++ mean the same thing when they form statements independently, they behave
differently when they are used in expressions on the right-hand side of an assignment statement. Consider
the following:
m = 5;
y = ++m;
In this case, the value of t and m would be 6. Suppose, if we write the above statements as
m = 5;
y = m++;
Then the value of y would be 5 and m would be 6. A prefix operator first adds 1 to the operand and then
the result is assigned to the variable on left. On the other hand, a postfix operator first assigns the value to
the variable on left then increments the operand.
3.1.6.
CONDITIONAL OPERATOR:
If exp1 is false, exp3 is evaluated and its value becomes the value of the expression. Note that only one of
the expressions (either exp2 or exp3) is evaluated.
Example program:
main()
{
int a, b, c;
printf(enter two values);
scanf(%d %d, &s, &b);
c = (a>b)? a:b;
printf(bigger value is %d, c);
}
OUTPUT:
3.1.7.
C has a distinction of supporting special operators known as bitwise operators for manipulation of
data at bit level. These operators are used for testing the bits, or shifting them right or left. Bitwise
operators may not be applied to float or double.
Operator
Meaning
&
Bitwise AND
Bitwise OR
Bitwise exclusive OR
<<
Shift left
>>
Shift right
Ones compliment
x&y
BITWISE OR: Bitwise OR is denoted by the symbol | (vertical bar). The | (vertical bar) operator
performs a bitwise OR on two integers. Each bit in the result is 1 if either of the corresponding bits in the
two input operands is 1. The following chart that defines |, defining OR on individual bits.
x|y
BITWISE XOR: Bitwise XOR is denoted by the symbol ^ (caret). The ^ (caret) operator performs a
bitwise exclusive-OR on two integers. Each bit in the result is 1 if one, but not both, of the corresponding
bits in the two input operands is 1. The following chart that defines Bitwise XOR
x^y
SHIFT LEFT: The << operator shifts its first operand left by a number of bits given by its second operand,
filling in new 0 bits at the right.
SHIFT RIGHT: The >> operator shifts its first operand right. If the first operand is unsigned, >> fills in 0
bits from the left, but if the first operand is signed, >> might fill in 1 bits if the high-order bit was already
1
ONEs COMPLIMENT: The ~ (tilde) operator performs a bitwise complement on its single integer
operand. Complementing a number means to change all the 0 bits to 1 and all the 1s to 0s.
3.1.8.
SPECIAL OPERATORS:
C supports some special operators of interest such as comma operator, size of operator, pointer
operators (& and *) and member selection operators (. And ->).
THE COMMA OPERATOR: The comma operator can be used to link the related expressions together. A
comma-linked list of expressions is evaluated left to right and the value of right-most expression ids the
value of the combined expression. For example the statement
value = (x=10, y=5, x+y);
First assigns the value 10 to x, then assigns 5 to y, and finally assigns 15(10+ 5) to value. Since comma
operator has lower precedence of all operators, the parentheses are necessary. Some applications of comma
operator:
In for loops:
for(n = 1, m = 10; n <= m; n++, m++)
in while loops:
while(c = getchar(), c!=10)
exchanging values:
t = x, x = y, y = t;
THE SIZEOF OPERATOR: The size of is a complier time operator and, when used with an operand, it
returns the number of bytes the operand occupies. The operand may be a variable, a constant or a data type
qualifier.
Examples:
m = sizeof(sum);
n = sizeof(long int)
The size of operator is normally used to determine the lengths of arrays and structures when their sizes are
not known to the programmer. It is also used to allocate memory space dynamically to variables during
execution of a program.
Each operator in C has a precedence associated with it. This precedence is used to determine how
an expression involving more than one operator is evaluated. There are distinct levels of precedence and an
operator may belong to one of the levels. The operators at the higher level of precedence are evaluated
first. The operators are of same precedence are evaluated either from left to right or from right to left,
depending on the level. This is known as the associativity property of an operator. The groups are listed in
the order of decreasing precedence (rank 1 indicates the highest precedence level and 15 the lowest)
3.2.1.
Operator
Description
Associativly
Prority
()
Function call
Left to Right
[]
Subscript
Left to Right
Logical Negation
Right to Left
Uniary plus
Uniary minus
++
Increment
--
Decrement
Directional
&
Address
(Type)
type casting
size of
size of an object
Multiplication
Left to Right
Division
Modulo Division
Addition
Left to Right
Subtraction
<<
Left shift
Left to Right
>>
Right shift
< or <=
Less than
Left to Right
> or >=
Greater than
Equity
Left to Right
!=
Not equal
&
Left to Right
Bit wise Or
Left to Right
10
&&
Logical And
Left to Right
11
Logical Or
Left to Right
12
Conditional
Left to Right
13
Assignment
Right To Left
14
Operational
14
Left to right
15
?:
Op
Assignment
(+=,-
=,*=,/=,%=)
,
Coma
The precedence rule say that the addition operator has the higher priority and the logical operator (&&)
and the relational operator (++ and <). Therefore, the addition of 10 and 15 is executed first. This is
equivalent to:
If (x == 25 && y < 10)
The next step is to determine whether x is equal to 25 and y is less than 10. If we assume a value of 20 for
x and 5 for y, then
x == 25 is false (0)
y < 10 is true (1)
Note that since the operator < enjoys a higher priority compared to +++, y, 10 is tested first and then x ==
25 is tested. Finally we get:
3.2.2.
An arithmetic expression without parentheses will be evaluated from left to right using the rules of
precedence of operators. There are two distinct priority levels of arithmetic operators.
High priority
* ? %
Low priority
+ -
The basic evaluation procedure includes two left to right passes through the expression. During the first
pass, the high priority operator (if any) is applied as they are encountered. During the second pass, the low
priority operators (if any) are applied as they are encountered.
CHAPTER 4
CONTROL STATEMENTS
Branching Statements
Looping Statements
4.1.
BRANCHING STATEMENTS:
4.1.1. If Statement:
This is the most simple form of the branching statements. It takes an expression in parenthesis
and a statement or block of statements. If the expression is true then the statement or block of
statements gets executed otherwise these statements are skipped.
Syntax:
if (expression)
statement;
or
if (expression)
{
Block of statements;
}
4.1.2. If else
The set of statements inside if block is executed only if the condition inside the
parenthesis of if comes true. Otherwise the set of statements in Else block will be executed.
Syntax:
if (expression)
{
Block of statements;
}
else
{
Block of statements;
}
Block of statements;
}
else
{
Block of statements;
}
}
else
{
Block of statements;
if (expression3)
{
Block of statements;
}
else
{
Block of statements;
}
}
statements1;
[case constant-expression2:
statements2;]
[case constant-expression3:
statements3;]
[default : statements4;]
}
4.2.
Looping Statements:
The test conditions should be carefully stated in order to perform the desired number of
loop executions. It is assumed that the test conditions will eventually transfer the control out of
the loop, due to some reason it does not do so, the control sets up an infinite loop and the body is
executed over and over again.
A looping process, in general, would include the following four steps:
The test may be either to determine whether the loop has been repeated the specified number of
times or to determine whether a particular condition has been met.
The C language provides for three loop constructs for performing loop operations. They are:
expression2 - Condtional expression, as long as this condition is true, loop will keep
executing.
Expression1 will be executed only once when the loop begins for the 1st iteration. Executes the
block of statements only if expression 2 is evaluated as true (1).
Benefits of for loop
The unique aspect of for loop is that one or more sections can be omitted, if necessary.
m = 5;
for( ; m != 100; )
{
printf(%d\n, m);
m = m + 5;
}
Both initialization and increment sections are omitted in the for statement. The
initialization has been done before the for statement and the control variable is incremented inside
the loop. In the above case the increment and initialization are left blank. However, the
semicolons separating the sections must remain. If the test condition is not present, the for
statement sets up and infinite loop. Such loops can be broken using break or goto statements in
the loop.
2.
The time delay can be set up using the for loop as follws,
for(j =1000; j > 0; j = j-1)
This loop is executed 1000 times without producing any output, it simply causes a time
delay.
The body of the loop is executed 10 times for n = 1,2,3.10 each time adding the square
of the value of n, which is incremented inside the loop. The test condition may also be written as
n<11
It helps to iterate set of statements for infinite number of times until power is down
It helps to run the code forever, as few embedded systems will not contain operating
system in it.
OUTPUT:
Enter a value 5
12345
4.3.
Break Statement:
We use break statement in both control structures and looping structures. When the
break statement is encountered inside a loop, the loop is immediately exited and the
program continues with the statement immediately following the loop. When the loops are
nested, the break statement would only exit from the loop containing it. That is, break is
exit only a single loop.
4.4.
Continue Statement:
Like the break which causes the loop to be terminated, the continue, as the name implies,
causes the loop to be continued with the next iteration after skipping any statements in between.
The continue statement tells the complier, SKIP THE FOLLOWING STATEMENT AND
CONTINUE WITH NEXT OTERATION. In while and do loops, continue causes the control to
go directly to the test condition and then to continue the iteration process. In the case of for loop,
the increment section of the loop is executed before the test-condition is evaluated.
CHAPTER 5
FUNCTION
A function is a block of code that has a name and it has a property that it is reusable i.e. it
can be executed from as many different points in a C Program as required. Function groups a
number of program statements into a unit and gives it a name. This unit can be invoked from
other parts of a program. A computer program cannot handle all the tasks by itself. Instead its
requests other program like entities called functions in C to get its tasks done. A function is a
self contained block of statements that perform a coherent task of same kind
The name of the function is unique in a C Program and is Global. It names that a function
can be accessed from any location within a C Program. We pass information to the function called
arguments specified when the function is called. And the function either returns some value to
the point it was called from or returns nothing. We can divide a long C program into small blocks
which can perform a certain task. A function is a self contained block of statements that perform a
coherent task of same kind.
5.1.
STRUCTURE OF A FUNCTION:
All parts are not essential. Some may be absent. For example, the argument list and its
associated argument declaration parts are optional. The return statement is the mechanism for
returning a value to the calling function. This is also an optional statement. Its absence indicates
that function does not return any value.
5.1.1. Function Header:
In the first line of the above code
int sum(int x, int y)
It has three main parts
1. The name of the function i.e. sum
2. The parameters of the function enclosed in parenthesis
3. Return value type i.e. int
The prototype of a function provides the basic information about a function which tells the
compiler that the function is used correctly or not. It contains the same information as the
function header contains. The prototype of the function in the above example would be like
int sum (int x, int y);
The only difference between the header and the prototype is the semicolon; there must the
semicolon at the end of the prototype. Functions groups a number of program statements into a
unit and gives it a name. This unit can be invoked from other parts of a program. A computer
program cannot handle all the tasks by itself. Instead its requests other program like entities
called functions in C to get its tasks done. A function is a self contained block of statements that
perform a coherent task of same kind.
PTO
Note: main is also a function which is used to indication to complier to where from the
completion should start.
5.5.
5.6.
Ex:
main()
{
sum();
}
void sum()
{
int a,b;
printf(Enter any 2 no's:);
scanf(%d,&a,&b);
printf(sum of numbers:%d, a+b);
}
The above function not sending any arguments to function definition and not receiving anything
from function definition.
5.7.
Function2()
Eg:
Function1()
Sending
Arguments
..............;
..............;
..............;
..............;
main()
..............;
{
Function2();
}
..............;
No return Value
..............;
}
int a,b;
printf(Enter any 2 no's:);
scanf(%d,&a,&b);
sum(a,b);
}
void sum(int a, int b) // a and b local variables to function definition
{
printf(sum of numbers:%d,a+b);
}
The above function we are sending arguments as a & b to function definition and are received
by formal parameters a and b and not returning to any information to the called function.
5.8.
Sending
Arguments
Function2()
{
..............;
..............;
..............;
..............;
returning Value to
..............;
called function
Function2();
Ex:
..............;
return(c);
}
main()
{
int a,b,c;
printf(Enter any 2 no's:);
scanf(%d,&a,&b);
c=sum(a,b);
}
The above function we are sending arguments as a & b to function definition and are received by
formal parameters a and b and returning the result to called function and received by the variable
C at to the called function.
5.9.
The explicit type specifier, corresponding to the data type required must be mentioned in
the function header. The general form of the function definition is:
Type-specifier function-name (argument list)
argument declaration;
{
The type specifier tells the compiler, the type of data the function is to return.
The called function must be declared at the start of the body in the calling function, like
any other variable. This is to tell the calling function the type of data that the function is
actually returning.
main()
{
float a, b, mul();
double div();
a = 12.345;
b = 9.82;
printf(%f\n, mul(a,b));
printf(%f\n, div(a,b));
Example program:
}
float mul(x,y)
float x,y;
{
return(x * y);
}
double div(p,q)
double p,q;
{
return(p/q);
}
The declaration part of main function declares not only variables but the functions mul
and div as well. This only tells the complier that mul will return a float type value and div a
double type value Parentheses that follow mul and div specify that they are functions instead of
variables. If we mismatch between the type of data that the called function returns and the type of
data that the calling function expects, we will have unpredictable results.
The functions print line() and value() do not return any values and therefore they were not
declared in the main. Although the program works nicely, we can declare them in them main with
the qualifier void. This states explicitly that the functions do not return values. This prevents any
main()
main()
{
int a,b,c;
float ratio();
scanf(%d%d%d,&a,&b,&c);
printf(%fn,ratio(a,b,c));
}
float ratio(x,y,z)
int x,y,z;
{
if(difference(y,z))
return(x/y-z));
else
return(0,0);
}
difference(p,q)
{
int p,q;
{
if(p!=q)
return(1);
else
return(0);
}
The above program calculates the ratio a/(b-c), and prints the result. we have the following three
functions:
main ()
ratio ()
difference ()
Main reads the values of a, b and c and calls the function ratio to calculate the value a/(b-c). This
ratio cannot be evaluated if (b-c) = o. Therefore, ratio calls another function difference to test
whether the difference (b-c) is zero or not. Difference returns 1, if b is not equal to c; otherwise
returns zero to the function ratio. In turn, ratio calculates the value a/(b-c) if it receives 1 returns
the result in float. In case, ratio receives zero form difference, it sends back 0.0 to main including
that (b-c) = 0.
Advantages:
It is easy to use.
Disadvantages:
It is slower than that of looping statements because each time function is called.
5.13. Macro
Definition of Macro
A macro is a fragment of code which has been given a name and performs the specified
operation by replacing the macro name with the text it has been used to represent
Different types of Macros
Macros with Parameters or object like macros
digit
The following representation will gives the idea with regards to macro declaration
Benefits of Macros
Define once use many criteria
The time taken to execute the code will be reduced
Increase the readability of the code
CHAPTER 6
POINTERS
6.1.
Introduction:
Pointers are another important feature of C language. Although they may appear a little
confusing for a beginner, they are a powerful tool and handy to use once they are mastered. There
are number of reasons for using pointers.
This reinforces the idea that pointers reach out an imaginary hand and point to some location in
the memory and it is more usual to speak of pointers in this way. The two operators * and & are
always written in front of a variable, clinging on, so that they refer, without doubt, to that one
variable. For instance, &x the address at which the variable x is stored. *ptr the contents of
the variable which is pointed to by ptr.
Consider the following c statement:
int x=2;
The above statement requests compiler to execute following steps:
Reserve the required space (depending upon the data type and computer configuration) for
And we can find out the starting location number of that reserve space by the following statement,
& operator is used find the address of the variable.
printf (Address is %u, &x);
Suppose we get the output of the above statement as 8621 which is the starting address of the
reserved space and hence we can represent the memory map for the variable i as:
If we run the same statement int x=2; again then the same steps would be following but the
memory location selected can be different from 8621. Reason being that the compiler randomly
selects the location from the large pool of free memory spaces and every time we select it, there
are rare chances of same memory location being selected.
The pointer, as the name suggests, is something which is pointing to or directing to
something. The pointer is used to store the address of another variable and the data type of the
pointer is same as data type of variable it is pointing to. As the variable which points to other
variable is called pointer and the variable which is pointed to by the pointer is called Pointee. We
represent the relation between the two as:
Note: Types of operations on pointers like addition of pointers, multiplying pointer by number,
dividing pointer by number are illegal.
in the memory which a points to. Nothing has been said about that yet. This kind of initialization
cannot possibly work and will most likely crash the program or corrupt some other data.
y=*p1**p2;
sum=sum+*p1;
z=5*-*p2/p1;
*p2 = *p2 + 10;
C language allows us to add integers to, subtract integers from pointers as well as to subtract one
pointer from the other. We can also use short hand operators with the pointers p1+=; sum+=*p2;
etc., we can also compare pointers by using relational operators the expressions such as p1 > p2,
p1==p2 and p1! =p2 are
allowed.
ptr1,ptr2;
int
a,b,x,y,z;
a=30;b=6;
ptr1=&a;
ptr2=&b;
x=*ptr1+*ptr26;
y=6*-*ptr1/*ptr2+30;
printf(nAddress
of
+%u,ptr1);
printf(nAddress
of
%u,ptr2);
printf(na=%d,
b=%d,a,b);
printf(nx=%d,y=%d,x,y);
ptr1=ptr1
70;
ptr2= ptr2;
printf(na=%d,
}
b=%d,a,b);
We would use this ip just like the one in the previous section: *ip gives us what ip points to,
which in this case will be the value in a [3]. Once we have a pointer pointing into an array, we can
start doing pointer arithmetic. Given that ip is a pointer to a [3], we can add 1 to ip: ip + 1; In C, it
gives a pointer to the cell one farther on, which in this case is a[4]. To make this clear, let's assign
this new pointer to another pointer variable: ip2 = ip + 1;
Now the picture looks like this:
* variable
name
First of all, specify the data type of data stored in the location, which is to identified by the
pointer. The asterisk tells the compiler that you are creating a pointer variable. Then specify the
name of variable. You can see in the given example, we have created an array of pointers of
maximum size 3. Then we have assigned the objects of array pointer.
array[0] = &x;
array[1] = &y;
array[2] = &z;
#include <stdio.h>
#include <conio.h>
main()
{
clrscr();
int *array[3];
int x = 10, y = 20, z = 30;
int i;
array[0] = &x;
array[1] = &y;
array[2] = &z;
for (i=0; i< 3; i++)
{
printf("The value of %d= %d ,address is %u\t \n", i, *(array[i]),array[i]);
}
getch();
return 0;
}
Output:
The information about how arrays are stored was not included just for interest. There is
another way of looking at arrays which follows the BCPL idea of an array as simply a block of
memory. An array can be accessed with pointers as well as with [] square brackets. The name of
an array variable, standing alone, is actually a pointer to the first element in the array.
For example: if an array is declared float numbers [34]; numbers is a pointer to the first floating
point number in the array; numbers is a pointer in its own right. (In this case it is type pointer to
float.) So the first element of the array could be accessed by writing:
numbers [0] = 22.3;
*numbers = 22.3;
Fixed Memory
Stack Memory
Heap Memory
Disadvantage: We have to manually de allocate the memory allocated using function like free or
delete, otherwise the memory which is not de allocated at the proper time goes to the garbage and
is not available for re-use.
Illustration with Simple Program:
int x=4;
main()
{
int z;
char* y;
y= malloc(6);
y=hello;
printf(%c, *y);
z = square(x);
printf(%d, z);
free(y);
}
int square(int k)
{
return k*k;
}
Now we see which variables in the program are stored where. In this program we have
different types of variables like x as global variable, z & k as local variable and as parameter to
the function and y is dynamically allocated variable. So x is stored in fixed memory, z & k are
stored in Stack Memory and the pointer y is also stored in stack memory while the 6 bytes
(allocated by malloc) which are pointees of pointer y are stored in heap memory.
The #pragma directive is the method specified by the C standard for providing additional
information to the compiler, beyond what is conveyed in the language itself. #pragma' is for
compiler directives that are machine-specific or operating-system-specific, i.e. it tells the compiler
to do something, set some option, take some action, override some default, etc. that may or may
not apply to all machines and operating systems
where setting is a configuration setting descriptor, e.g., WDT, and state is a textual
description of the desired state, e.g., OFF. The value field is a numerical value that can
be used in preference to a descriptor.
Consider the following PIC18-only examples.
#pragma config WDT = ON // turn on watchdog timer
#pragma config WDT = 1 // an alternate form of the above
#pragma config WDTPS = 0x1A // specify the timer postscale value
you to dynamically change their size at runtime, but they require more advanced techniques
such as pointers and memory allocation.
b. Declaration of a array
Arrays can be declared using any of the data types available in C. Array size must be declared
using constant value before initialization. A single dimensional array will be useful for
simple grouping of data
Syntax: <data type> array_name[size_of_array];
Sample code : char game_map[4];
c. Initialization of array
Initializing Single Dimension Arrays
Array can be initialized in two ways, initializing on declaration or initialized by assignment.
Initializing on Declaration
If you know the values you want in the array at declaration time, you can initialize an array as
follows:
Syntax:
<data type> array_name[size_of_array] = {element 1, element 2, ...};
Sample code:
char game_map[3] = {'S', 'R', 'D'};
d.
A structure is a collection of variables under a single name. The variables can be of different
types, and each has a name which is used to select it from the structure. A structure is a
convenient way of grouping several pieces of related information together.A structure can be
defined as a new named type, thus extending the number of available types. It can use other
structures, arrays or pointers as some of its members
b. Structure definition
Here is the common syntax of structure definition:
struct struct_name{ structure_member1;
structure_member2;
.
structure_member n
};
Structure declaration
struct struct_name{ structure_member1;
structure_member2;
.
structure_member n
}var1,var2 var n;
OR
struct struct_name var1,var2 var n
c. Accessing a structure
<Var_name>.<structure_member>
d. Initialization of structure
Structure members can be initialized when you declare a variable of your structure:
Sample code:
struct object player1 = {player1, 0, 0};
The above declaration will create a struct object called player1 with an id equal to player1,
xpos equal to 0, and ypos equal to 0.
To access the members of a structure, you use the . (scope resolution) operator. Shown below
is an example of how you can accomplish initialization by assigning values using the scope
resolution operator:
Sample Code:
Union are like structures, containing the members whose individual data types may differ
from one another. However, the members that compose a union shall share the same storage area
within the computers memory, whereas each member within a structure is assigned its own
unique storage area. Thus, unions are used to conserve memory.
The general syntax of the union is as given below,
union tag{
member1;
member 2;
--member m
}variable 1, varibale2, . . . ., variable n;
union is a required keyword, tag is the name that appeared in the union definition, member1
member n are the union members and variable 1, variable 2, variable n are union variables of type
tag.
An individual union member can be accessed in the same manner as an individual structure
members, using the operators ->and.
Point to remember:
1. Like a structure, a union is also a derived data type.
2. The members of a union share a single storage space.
development
Definition of a Enumerators
An enumeration consists of a set of named integer constants. An enumeration type
declaration gives the name of the (optional) enumeration tag and defines the set of named
integer identifiers (called the "enumeration set," "enumerator constants," "enumerators," or
"members"). A variable with enumeration type stores one of the values of the enumeration
set defined by that type.
Variables of enum type can be used in indexing expressions and as operands of all arithmetic
and relational operators. Enumerations provide an alternative to the #define preprocessor
directive with the advantages that the values can be generated for you and obey normal
scoping rules.
In ANSI C, the expressions that define the value of an enumerator constant always have int
type; thus, the storage associated with an enumeration variable is the storage required for a
single int value. An enumeration constant or a value of enumerated type can be used
anywhere the C language permits an integer expression.
Declaration of a Enumerators
Syntax
enum-specifier:
enum identifier opt { enumerator-list }
enum identifier
Example:
enum DAY
/* Defines an enumeration type */
{
saturday,
/* Names day and declares a
*/
sunday = 0, /* variable named workday with */
monday,
/* that type
*/
tuesday,
wednesday, /* wednesday is associated with 3 */
thursday,
friday
} workday;
b.