Programming in C&DS TextBOOK 1
Programming in C&DS TextBOOK 1
Editor
Prof. K. Shyamala
Professor & Head
Department of Computer Science Engineering,
University College of Engineering, OU, Hyderabad
.
Course Writers
Mr. M. Narendar Reddy, M.C.A., M.Tech.,
Asst.Professor,
Department of Computer Science Engineering,
University College of Engineering, OU, Hyderabad
Director
Prof. Chintha Ganesh
UNIT I
Introduction to C Language – Background, C identifiers, Data Types, Operators, Variables,
Constants, Input / Output, Expressions, C Programs, Precedence and Associativity,
Evaluating Expressions, Types of Conversions, Statements, Bitwise Operators.
Selection : Logical Data and Operators, if-else, switch Statements, Standard Functions.
Repetitions : Loops, while, for, do-while statements, Loop examples, Break, Continue, go to.
UNIT II
Arrays – Concepts, Using Arrays in C, Inter-Function Communication, Array Applications,
Two-Dimensional Arrays, Multidimensional Arrays, Linear and Binary Search, Selection,
Bubble, Insertion Sorts.
Functions : Function Basics, User Defined Functions, Inter Function Communication,
Standard Functions, Scope, Storage Classes-Auto, Register, Static, Extern, Scope Rules, and
Type Qualifiers.
Recursion – Recursive Functions, Terminating Condition, Preprocessor Commands.
UNIT III
Pointers – Introduction, Pointers to Pointers, Compatibility, L value and R value, Arrays and
Pointers, Pointer Arithmetic and Arrays.
Call-by-reference : Passing Arrays to a Function, Dynamic Memory Allocation: Memory
Allocation Functions, Arrays of Pointers.
Strings – Concepts, String input/Output Functions, Arrays of Strings, String Manipulation
Functions, The Type Definition (type def), Enumerated Types.
UNIT IV
Structure : Definition and Initialization of Structures, Accessing Structures, Nested
Structures, Arrays of Structures, Structures and Functions, Pointers to Structures, Self
Referential Structures and Unions.
Input and Ouput :Files, Streams, Standard Library Input Output Functions, Character Input
Output Functions.
UNIT V
Data Structures – Introduction to Data Structures, abstract data types, Linear List – singly
linked list implementation, insertion, deletion and searching operations on linear list, Stacks-
Operations, array and linked representations of stacks, stack application-infix to postfix
conversion, postfix expression evaluation, recursion implementation, Queues-operations,
array and linked representations.
Suggested Reading :
1. B.A.Forouzan and R.F. Gilberg, C Programming and Data Structures, 3rd Edition,
Cengage Learning, 2007.
2. Kernighan B W and Ritchie DM, The C Programming Language, 2nd Edition,
Prentice Hall of India, 2006.
i
PROGRAMMING IN C AND DATA STRUCTURES
TABLE OF CONTENTS
1.5 OPERATORS 6
1.6 C VARIABLES 17
1.7 C PROGRAMMING ENVIRONMENT 24
1.9 SELECTION 28
1.10 REPETITION 32
UNIT – II
2.1 ARRAYS 40
2.2 FUNCTIONS 43
2.3 RECURSION 50
UNIT - III
3.1 POINTERS 58
3.2 STRINGS 72
UNIT- IV
4.1 STRUCTURES 78
ii
4.3 ARRAY OF STRUCTURES 80
4.7 UNIONS 84
UNIT-V
iii
UNIT - I
PROGRAMMING IN C AND DATA STRUCTURES
UNIT-I
The low level languages are machine level and assembly level language. In machine level
language, computer only understand digital numbers i.e. in the form of 0 and 1. So,
instruction given to the computer is in the form binary digit, which is difficult to implement
instruction in binary code. This type of program is not portable, difficult to maintain and also
error prone. The assembly language is modified version of machine level language, where
instructions are given in English like word as ADD, SUM, MOV etc. It is easy to write and
understand but not understand by the machine. Assembler is a program used to translate the
assembly language program into low level language. In the assembly level language, the data
1|P a g e
is stored in the computer register, which varies for different computer. Hence it is not
portable.
High level language: These languages are machine independent, means it is portable. The
languages in this category C, C++, C#, JAVA, Pascal, COBOL, Fortran etc. A translator is
software which is used to translate high level language as well as low level language in to
machine level language. Three types of translators are Compiler, Interpreter and
Assembler.
Compiler and interpreter are used to convert the high level language into machine level
language. The program written in high level language is known as source program and the
corresponding machine level language program is called as object program. Both compiler
and interpreter perform the same task but there working is different. Compiler read the
program at-a-time and searches the error and lists them. If the program is error free then it is
converted into object program. When program size is large then compiler is preferred.
Whereas interpreter read only one line of the source code and convert it to object code
C uses the uppercase letters A to Z, the lowercase letters a to z, the digits 0 to 9, and certain
special characters as building blocks to form basic program elements (e.g., constants,
variables, operators, expressions, etc.). The special characters are listed below.
+ - * / % & # ?
^ || \ | < > ( )
! ~ (blank space)
Most versions of the language also allow certain other characters, such as @ and $, to be
included within strings and comments.
C uses certain combinations of these characters, such as \b, \n and \t to represent special
conditions such as backspace, newline and horizontal tab, respectively. These character
combinations are known as escape sequences. Each escape sequence represents a single
character, even though it is written as two or more characters.
2|P a g e
1.3 C IDENTIFIERS AND KEYWORDS
Identifiers are names that are given to various program elements, such as variables,
functions and arrays. Identifiers consist of letters and digits, in any order, except that the first
character must be a letter. Both upper and lowercase letters are permitted, though common
usage favors the use of lowercase letters. Upper and lowercase letters are not
interchangeable (i.e., an uppercase letter is not equivalent to the corresponding lowercase
letter.) The underscore character ( - ) can also be included, and is considered to be a letter.
An underscore is often used in the middle of an identifier.
EXAMPLE 1:
The following names are not valid identifiers for the reasons stated.
There are certain reserved words, called keywords, that have standard, predefined meanings
in C. These keywords can be used only for their intended purpose; they cannot be used as
programmer-defined identifiers. The standard keywords are:
3|P a g e
1.4 C DATA TYPES
DATA RANGE OF
TYPE VALUES
Integer Type:
Integers are whole numbers with a machine dependent range of values. C language has three
classes of integer storage, namely, short int, int and long int. All of these data types have
signed and unsigned forms. A short int requires half the space than normal integer values.
Unsigned numbers are always positive and consume all the bits for the magnitude of the
number. The long and unsigned integers are used to declare a long range of values.
Floating point number represents a real number with 6 digits precision. Floating point
numbers are denoted by the keyword float. When the accuracy of the floating point number is
insufficient, the double data type can be used to define the number. The double is same as
float but with longer precision. To extend the precision further we can use long double which
consumes 80 bits of memory space.
4|P a g e
Void Type:
Using void data type, we can specify the type of a function. It is a good practice to avoid
functions that does not return any values to the calling function.
Character Type:
A single character can be defined as a character type of data. Characters are usually stored in
8 bits of internal storage. The qualifier signed or unsigned can be explicitly applied to char.
While unsigned characters have values between 0 and 255, signed characters have values
from –128 to 127.
Unsigned 8 0 to 255
Char
Unsigned 8 0 to 255
short int
Unsigned 32 0 to 4294967295
5|P a g e
long int
1.5 OPERATORS
1. Arithmetic Operators
2. Relational Operators
3. Logical Operators
4. Assignment Operators
5. Increment and Decrement Operators
6. Conditional Operators
7. Bitwise Operators
8. Special Operators
All the basic arithmetic operations can be carried out in C. All the operators have almost the
same meaning as in other languages. Both unary and binary operations are available in C
language. Unary operations operate on a single operand.
Operator Meaning
* Multiplication
/ Division
% Modulus Operator
6|P a g e
-x + y
a*b+c
-a * b
a, b, c, x, y are known as operands. The modulus operator is a special operator in C language
which evaluates the remainder of the operands after division.
Integer Arithmetic
When an arithmetic operation is performed on two whole numbers or integers than such an
operation is called as integer arithmetic. It always gives an integer as the result. Let x = 27
and y = 5 be 2 integer numbers. Then the integer operation leads to the following results.
x + y = 32
x – y = 22
x * y = 115
x%y=2
x/y=5
When an arithmetic operation is preformed on two real numbers or fraction numbers such an
operation is called floating point arithmetic. The floating point results can be truncated
according to the properties requirement. The remainder operator is not applicable for floating
point arithmetic operands.
x + y = 18.0
x – y = 10.0
x * y = 56.0
x / y = 3.50
When one of the operand is real and other is an integer and if the arithmetic operation is
carried out on these 2 operands then it is called as mixed mode arithmetic. If any one operand
is of real type then the result will always be real thus 15/10.0 = 1.5
7|P a g e
1.5.2 Relational Operators
Relational operators used to compare the relationship between operands. C supports the
following relational operators.
Operator Meaning
== is equal to
A simple relational expression contains only one relational operator and takes the following
form.
exp1 relational operator exp2
Where exp1, exp2 are expressions, which may be simple constants, variables or combination
of them.
C has the following logical operators, used to compare or evaluate logical and relational
expressions.
Operator Meaning
|| Logical OR
! Logical NOT
8|P a g e
Logical AND (&&)
Example
a > b && x = = 10
The expression to the left is a > b and that on the right is x == 10 the whole expression is true
only if both expressions are true i.e., if a is greater than b and x is equal to 10.
Logical OR (||)
The logical OR is used to combine two expressions or the condition evaluates to true if any
one of the expressions is true.
Example
a < m || a < n
The expression evaluates to true if any one of them is true or if both of them are true. It
evaluates to true if a is less than either m or n and when a is less than both m and n.
The logical not operator takes single expression and evaluates to true if the expression is false
and evaluates to false if the expression is true. In other words it just reverses the value of the
expression.
For example
! (x >= y)
The Assignment Operator evaluates an expression on the right of the expression and
substitutes it to the value or variable on the left of the expression.
9|P a g e
Example
Here var is a variable, exp is an expression and oper is a C binary arithmetic operator. The
operator oper = is known as shorthand assignment operator
Example
x += 1 is same as x = x + 1
The commonly used shorthand assignment operators are as follows:
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
Example:
#define N 100 //creates a variable N with constant value 100
#define A 2 //creates a variable A with constant value 2
10 | P a g e
{ //evaluate or do the following
printf(“%d \n”, a); //print the current value of a
a *= a; // a = a * a
} //end of the loop
} //end of the program
Output
2
4
16
The increment and decrement operators are one of the unary operators which are very useful
in C language. They are extensively used in for and while loops. The syntax of the operators
is given below
1. ++ variable name
2. variable name++
3. – variable name
4. variable name –
The increment operator ++ adds the value 1 to the current value of operand and the decrement
operator – – subtracts the value 1 from the current value of operand. ++variable name and
variable name++ mean the same thing when they form statements independently, behave
differently when they are used in expression on the right hand side of an assignment
statement.
Then, the value of y will be 5 and that of m will be 6. A prefix operator first adds 1 to the
operand and then the result is assigned to the variable on the left. On the other hand, a postfix
operator first assigns the value to the variable on the left and then increments the operand.
11 | P a g e
1.5.6 Conditional Operator or Ternary Operator ( ?: )
The conditional operator consists of two symbols, the question mark (?) and the colon (:) .
The syntax for a ternary operator is as follows:
exp1 is evaluated first. If the expression is true then exp2 is evaluated & its value becomes
the value of the expression. If exp1 is false, exp3 is evaluated and its value becomes the value
of the expression.
For example
a = 10;
b = 15;
x = (a > b) ? a : b
Here ‘x’ will be assigned to the value of ‘b’. The condition follows that the expression is
false therefore b is assigned to x.
Output
Input two integers: 34, 45
The largest of two numbers is 45
12 | P a g e
operators are used for testing, complementing or shifting bits to the right on left. Bitwise
operators may not be applied to a float or double.
Operator Meaning
| Bitwise OR
^ Bitwise Exclusive
Type char is one byte in size. This means it is made up of 8 distinct bits or binary digits
normally designated as illustrated below with Bit 0 being the Least Significant Bit (LSB) and
Bit 7 being the Most Significant Bit (MSB). The value represented below is 13 in decimal.
An integer on a 16 bit OS is two bytes in size and Bit 15 will be the MSB while on a 32 bit
system the integer is four bytes in size with Bit 31 as the MSB.
If any two bits in the same position are 1 then the resultant bit in that position is 1 otherwise it
is 0.
For Example :
1011 0010 (178)
& 0011 1111 (63)
= 0011 0010 (50)
Bitwise OR (|)
Note : If either bit in corresponding positions is 1 then resultant bit in that position is 1.
For Example :
1011 0010 (178)
| 0011 1111 (63)
= 1011 1111 (191)
13 | P a g e
Bitwise XOR ( ^)
Note: If the bits in corresponding positions are different then the resultant bit is 1.
For Example :
1011 0010 (178)
^ 0011 1111 (63)
= 1000 1101 (141)
For Example :-
2 << 2 = 8
i.e.
0000 0010 becomes 0000 1000
Ones Complement
For Example :-
1101 0011 becomes 0010 1100
The bitwise operators are most commonly used in system level programming where
individual bits of an integer will represent certain real life entities which are either on or off,
one or zero. The programmer will need to be able to manipulate individual bits directly in
these situations.
A mask variable which allows us to ignore certain bit positions and concentrate the operation
only on those of specific interest to us is almost always used in these situations. The value
given to the mask variable depends on the operator being used and the result required.
14 | P a g e
char ch = 89 ; // any value
i |= mask ;
C supports some special operators of interest such as comma operator, size of operator,
pointer operators (& and *) and member selection operators (. and ->). The size of and the
comma operators are discussed in this section.
First assigns 10 to x and 5 to y and finally assigns 15 to value. Since comma has the lowest
precedence in operators the parenthesis is necessary. Some examples of comma operator are
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;
15 | P a g e
Example
m = sizeof (sum);
n = sizeof (long int);
k = sizeof (235L);
The size of operator is normally used to determine the length 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 the execution of the program.
Example: Program that employs different kinds of operators. The results of their evaluation
are also shown in comparison.
Notice the way the increment operator ++ works when used in an expression. In the statement
c = ++a – b; new value a = 16 is used thus giving value 6 to C. That is, a is incremented by 1
before using in expression.
However in the statement d = b++ + a; The old value b = 10 is used in the expression. Here b
is incremented after it is used in the expression.
We can print the character % by placing it immediately after another % character in the
control string. This is illustrated by the statement.
c>d?1:0
Assumes, the value 0 when c is less than d and 1 when c is greater than d.
16 | P a g e
1.6 C VARIABLES
A variable is a named piece of memory which is used to hold a value which may be modified
by the program. A variable thus has three attributes that are of interest to us : its type, its
value and its address.
The variable’s type informs the type and range of values it can represent and how much
memory is used to store that value. The variable’s address informs where in memory the
variable is located.
All C variables must be declared as follows:
type variable-list ;
For Example :
int i ;
char a, b, ch ;
void main()
{
int i, j ;
...
}
A local variable is created i.e. allocated memory for storage upon entry into the code block in
which it is declared and is destroyed i.e. its memory is released on exit. This means that
values cannot be stored in these variables for use in any subsequent calls to the function .
When declared outside function, they are termed as global variables and are visible
throughout the file or have file scope. These variables are created at program start-up and can
be used for the lifetime of the program.
int i ;
void main()
{
...
}
When declared within the braces of a function they are termed the formal parameters of the
function.
int func1( int a, char b ) ;
17 | P a g e
Variable Names
Names of variables and functions in C are called identifiers and are case sensitive. The first
character of an identifier must be either a letter or an underscore while the remaining
characters may be letters, numbers, or underscores. Identifiers in C can be up to 31 characters
in length.
Initialising Variables
When variables are declared in a program it just means that an appropriate amount of
memory is allocated to them for their exclusive use. This memory however is not initialized
to zero or to any other value automatically and so will contain random values unless
specifically initialized before use.
For Example :-
char ch = 'a' ;
double d = 12.2323 ;
int i, j = 20 ; /* note in this case i is not initialised */
Constants
C constant is usually just the written version of a number. For example 1, 0, 5.73, 12.5e9.
We can specify our constants in octal or hexadecimal, or force them to be treated as long
integers.
Character constants are usually just the character enclosed in single quotes; 'a', 'b', 'c'. Some
characters can't be represented in this way, so we use a 2 character sequence.
In addition, a required bit pattern can be specified using its octal equivalent.
18 | P a g e
Character constants are rarely used, since string constants are more convenient. A string
constant is surrounded by double quotes e.g. "Brian and Dennis". The string is actually stored
as an array of characters. The null character '\0' is automatically placed at the end of such a
string to act as a string terminator.
Constant is a special types of variable which can not be changed at the time of execution.
Syntax:
This section introduces some of the more common input and output functions provided in the
C standard library.
printf()
The printf() function is used for formatted output and uses a control string which is made up
of a series of format specifiers to govern how it prints out the values of the variables or
constants required. The more common format specifiers are given below
Example 1:
int i ;
printf( "%d", i ) ;
The printf() function takes a variable number of arguments. As shown in the example 1, two
arguments are required, the format string and the variable i. The value of i is substituted for
the format specifier %d which specifies how the value is to be displayed, in this case as a
signed integer.
Example 2 :-
int i = 10, j = 20 ;
19 | P a g e
char ch = 'a' ;
double f = 23421.2345 ;
Field width specifiers are used in the control string to format the numbers or characters to
print appropriately .
For Example :-
int i = 15 ;
float f = 13.3576 ;
printf( "%3d", i ) ; /* prints "_15 " where _ indicates a space
character */
printf( "%6.2f", f ) ; /* prints "_13.36" which has a total width
of 6 and displays 2 decimal places */
printf( “%*.*f”, 6,2,f ) ; /* prints "_13.36" as above. Here * is used as replacement
character for field widths */
There are also a number of flags that can be used in conjunction with field width specifiers to
modify the output format. These are placed directly after the % sign. A - (minus sign) causes
the output to be left-justified within the specified field, a + (plus sign) displays a plus sign
preceding positive values and a minus preceding negative values, and a 0 (zero) causes a field
to be padded using zeros rather than space characters.
scanf()
This function is similar to the printf function except that it is used for formatted input.
The format specifiers have the same meaning as for printf() and the space character or
the newline character are normally used as delimiters between different inputs.
20 | P a g e
For Example :-
int i, d ;
char c ;
float f ;
The & character is the address of operator in C, it returns the address in memory of the
variable it acts on
Note that while the space and newline characters are normally used as delimiters between
input fields the actual delimiters specified in the format string of the scanf statement must be
reproduced at the keyboard.
The scanf function has a return value which represents the number of fields.
For Example :-
num = scanf( “%c %d”, &ch, &i );
This scanf call requires two fields, a character and an integer, to be read in so the value
placed in num after the call should be 2 if this was successful. However if the input was “a
bc” then the first character field will be read correctly as ‘a’ but the integer field will not be
converted correctly as the function cannot reconcile “bc” as an integer. Thus the function will
return 1 indicating that one field was successfully converted. Thus to be safe the return value
of the scanf function should be checked always and some appropriate action taken if the
value is incorrect.
These functions are used to input and output single characters. The getchar() function reads
the ASCII value of a character input at the keyboard and displays the character while
putchar() displays a character on the standard output device i.e. the screen.
For Example :-
char ch1, ch2 ;
ch1 = getchar() ;
21 | P a g e
ch2 = 'a' ;
putchar( ch2 ) ;
Note : The input functions described above, scanf() and getchar() are termed buffered input
functions. This means that whatever the user types at the keyboard is first stored in a data
buffer and is not actually read into the program until either the buffer fills up and has to be
flushed or until the user flushes the buffer by hitting RET whereupon the required data is read
into the program. The important thing to remember with buffered input is that no matter how
much data is taken into the buffer when it is flushed the program just reads as much data as it
needs from the start of the buffer allowing whatever else that may be in the buffer to be
discarded.
For Example :-
char ch1, ch2;
In the above code segment if the input is "abcdef”, the first two characters are read into the
variables all the others being discarded, but control does not return to the program until the
RET is hit and the buffer flushed. If the input was "aRET" then a would be placed in ch1 and
RET in ch2.
_flushall()
The _flushall function writes the contents of all output buffers to the screen and clears
the contents of all input buffers. The next input operation (if there is one) then reads new data
from the input device into the buffers.
This function should be used always in conjunction with the buffered input functions to clear
out unwanted characters from the buffer after each input call.
These functions perform the same operation as getchar() except that they are unbuffered input
functions i.e. it is not necessary to type RET to cause the values to be read into the program
they are read in immediately the key is pressed. getche() echoes the character hit to the screen
while getch() does not.
For example :-
char ch ;
ch = getch() ;
22 | P a g e
First C Program
A C program consists of one or more functions or code modules. These are essentially groups
of instructions that are to be executed as a unit in a given order and that can be referenced by
a unique name. Each C program must contain a main() function. This is the first function
called when the program starts to run. Note that while "main" is not a C keyword and hence
not reserved it should be used only in this context.
A program in C is traditionally arranged in the following order but not strictly as a rule.
Function definitions
Consider first a simple C program which simply prints a line of text to the computer screen.
#include <stdio.h>
void main()
{
/* This is how comments are implemented in C
to comment out a multi-line
text as comment */
// or like this for a single line comment
As you can see this program consists of just one function the mandatory main function. The
parentheses, ( ), after the word main indicate a function while the curly braces, { }, are used
to denote a block of code, i.e the sequence of instructions that make up the function.
Comments are contained within a /* ... */ pair in the case of a block comment or a double
forward slash, //, used to comment out the remains of a single line of test.
The line
printf("This is my First C Program \n " ) ;
23 | P a g e
is the only C statement in the program and must be terminated by a semicolon.
The statement calls a function called printf which causes its argument, the string of
text within the quotation marks, to be printed to the screen. The characters \n are not printed
as these characters are interpreted as special characters by the printf function in this case
printing out a newline on the screen. These characters are called escape sequences in C and
cause special actions to occur and are preceded always by the backslash character, \ .
All C compiler include a library of standard C functions such as printf which allow the
programmer to carry out routine tasks such as I/O, maths operations, etc. but which are not
part of the C language, the compiled C code merely being provided with the compiler in a
standard form.
Header files must be included which contain prototypes for the standard library functions and
declarations for the various variables or constants needed. These are normally denoted by a .h
extension and are processed automatically by a program called the Preprocessor prior to the
actual compilation of the C program.
The line
#include <stdio.h>
instructs the preprocessor to include the file stdio.h into the program before compilation so
that the definitions for the standard input/output functions including printf will be present for
the compiler. The angle braces denote that the compiler should look in the default
“INCLUDE” directory for this file. A pair of double quotes indicate that the compiler should
search in the specified path e.g.
#include “d:\myfile.h”
Note : C is case sensitive i.e. printf() and Printf() would be regarded as two different
functions.
The first phase of development involves the creation and editing of a file containing the
appropriate C instructions which will be stored using a file extension of .c normally to invoke
the C compiler, e.g. fname.c.
The next step is to take the C program and to compile it into object code or machine language
code. The C compiler includes the aforementioned preprocessor which is called automatically
before the code translation takes place. This preprocessor acts on special commands or
directives from the programmer to manipulate the text of the C code before compilation
commences. These directives might involve including other source files in the file to be
compiled, replacing special symbols with specific replacement text, etc. Once this is done the
24 | P a g e
C code is translated into object code and stored in a file with the extension .obj, e.g.
fname.obj.
The final phase in building the executable program is called linking. After the compilation
stage the C code has been translated into machine recognizable code but is in a somewhat
unconnected state. The program invariably contains references to standard library functions
or functions contained in other libraries or modules which must be connected to the C
program at link time. This simply involves linking the machine code for these functions with
the program’s object code to complete the build process and produce an executable file with
an extension .exe e.g. fname.exe.
The executable program can be loaded and run from within the programming environment
itself or may be run from the host environment directly. If it executes as expected that is the
end of the task. However if this does not happen it may require the use of the debugger to
isolate any logical problems. The debugger allows us to step through the code instruction by
instruction or up to predefined break-points and to look at the values of variables in the code
in order to establish where errors are introduced.
25 | P a g e
1.8 PRECEDENCE AND ASSOCIATIVITY OF OPERATORS
When several operations are combined into one C expression the compiler has to rely on a
strict set of precedence rules to decide which operation will take preference. The precedence
of C operators is given below.
Operators at the top of the table have highest precedence and when combined with other
operators at the same expression level will be evaluated first.
2 + 10 * 5 ;
Here * and + are being applied at the same level in the expression but which comes first ?
The answer lies in the precedence table where the * is at a higher level than the + will
consider first.
When two operators with the same precedence level are applied at the same expression level
the associativity of the operators comes into play.
2+3-4;
the + and - operators are at the same precedence level but associate from left to right and so
the addition will be performed first. However in the expression
x=y=2;
26 | P a g e
as we have noted already the assignment operator associates from right to left and so the
rightmost assignment is first performed.
Note : As we have seen already parentheses can be used to supersede the precedence rules
and force evaluation along the lines we require. For example to force the addition in 2 + 10 *
5 ; to be carried out first we would write it as (2 + 10) * 5;
1. If one operand is long double, the other will be converted to long double and result
....will be long double.
.
2. If one operand is double, the other will be converted to double and result will be
double.
.
3. If one operand is float, the other will be converted to float and result will be float.
.
4. If one of the operand is unsigned long int, the other will be converted into unsigned
....long int and result will be unsigned long int.
.
5. If one operand is long int and other is unsigned int then .
.... a. If unsigned int can be converted to long int, then unsigned int operand will be
.........converted as such and the result will be long int.
.....b. Else Both operands will be converted to unsigned long int and the result will be
.........unsigned long int.
6. If one of the operand is long int, the other will be converted to long int and the result
will be long int. .
7. If one operand is unsigned int the other will be converted to unsigned int and the
.....result will be unsigned int.
27 | P a g e
Explicit Conversion
Many times there may arise a situation where we want to force a type conversion in a way
that is different from automatic conversion,
Consider for example the calculation of number of female and male students in a class
Since if female_students and male_students are declared as integers, the decimal part will be
rounded off and its ratio will represent a wrong figure. This problem can be solved by
converting locally one of the variables to the floating point as shown below.
The operator float converts the female_students to floating point for the purpose of evaluation
of the expression. Then using the rule of automatic conversion, the division is performed by
floating point mode, thus retaining the fractional part of the result. The process of such a local
conversion is known as explicit conversion or casting a value. The general form is
(type_name) expression
1.9 SELECTION
if statement
The if statement is the most general method for allowing conditional execution in C.
Syntax : if ( condition )
statement body ;
else
statement body ;
or just :
if ( condition )
statement body ;
In the first more general form of the statement one of two code blocks are to be executed. If
the condition evaluates to TRUE the first statement body is executed otherwise for all other
situations the second statement body is executed.
28 | P a g e
In the second form of the statement the statement body is executed if the condition evaluates
to TRUE. No action is taken otherwise.
For Example : Program to perform integer division avoiding the division by zero case.
#include <stdio.h>
void main()
{
I nt nr, dr ;
if ( dr != 0 )
printf( "%d / %d = %d \n", nr, dr, nr/dr );
else
printf( "Invalid operation - unable to divide by zero \n” );
}
As with all other control statements the statement body can also involve multiple statements,
again contained within curly braces.
Example :- Program to count the number of occurrences of the letter 'a' in an input stream of
characters terminated with a carriage return.
#include <stdio.h>
void main()
{
int count = 0, total = 0 ;
char ch ;
while ( ( ch = getchar() ) != 13 ) // 13 is ASCII value for carriage return
{
if ( ch == 'a' )
{
count ++ ;
printf( “\n Retrieved letter ‘a’ number %d\n”, count ) ;
}
total ++ ;
_flushall() ;
}
printf( "\n\n %d letters a typed in a total of %d letters.", count, total ) ;
}
29 | P a g e
Nested if statements
if - else statements like all other decision or iteration statements in C can be nested to
whatever extent is required. Care should be taken however to ensure that the if and else parts
of the statement are matched correctly -- the rule to follow is that the else statement matches
the most recent unmatched if statement.
For Example :-
if ( x > 0 )
if ( x > 10 )
puts ( " x is greater than zero and also greater than 10 ");
else
puts ("x is greater than zero but less than or equal to 10");
The else clause matches the most recent unmatched if clause, if ( x > 10 ). For more clarity
the above section could be rewritten as follows using curly braces with no execution penalty
:-
if ( x > 0 )
{
if ( x > 10 )
puts ( " x is greater than zero and also greater than 10 ");
else
puts ( "x is greater than zero but less than or equal to 10 ");
}
if - else - if ladder
When a programming situation requires the choice of one case from many different cases
successive if statements can be tied together forming what is sometimes called an if-else-if
ladder.
Syntax : if ( condition_1 )
statement_1 ;
else if ( condition_2 )
statement_2 ;
else if ( condition_3 )
statement_3 ;
...
else if ( condition_n )
statement_n ;
30 | P a g e
else
statement_default ;
Essentially what we have here is a complete if-else statement hanging onto each else
statement working from the bottom up.
void main()
{
int secret = 101, guess, count = 0 ;
printf( “\n Try and guess my secret number.\n\n” ) ;
while ( 1 ) // infinite loop until we break out of it
{
printf( “\n Make your guess: ” ) ;
scanf( “%d”, &guess ) ;
count ++ ;
if ( guess < secret )
printf( “\nA little low. Try again.” ) ;
else if ( guess > secret )
printf( “\nA little high. Try again.” ) ;
else
{
printf( “\nOk you got it and only on attempt %d.”, count );
break ;
}
}
}
Switch Case
This is another form of the multi way decision. It is well structured, but can only be used in
certain cases where;
Only one variable is tested, all branches must depend on the value of that variable.
The variable must be an integral type. (int, long, short or char).
Each possible value of the variable can control a single branch. A final, catch all,
default branch may optionally be used to trap all unspecified cases.
Example:
int number;
/* Estimate a number as none, one, two, several, many */
31 | P a g e
{ switch(number) {
case 0 :
printf("None\n");
break;
case 1 :
printf("One\n");
break;
case 2 :
printf("Two\n");
break;
case 3 :
case 4 :
case 5 :
printf("Several\n");
break;
default :
printf("Many\n");
break;
}
}
Each interesting case is listed with a corresponding action. The break statement prevents any
further statements from being executed by leaving the switch. Since case 3 and case 4, there
is no break statement, they continue on allowing the same action for several values of
number.
Both if and switch constructs allow the programmer to make a selection from a number of
possible actions.
1.10 REPETITION
Looping is a way by which we can execute set of statements more than one times
continuously .In C, there are mainly three types of loops are in use :
while Loop
do while Loop
For Loop
while statement
The while statement is typically used in situations where it is not known in advance how
many iterations are required.
32 | P a g e
Syntax : while ( condition )
statement body ;
FALSE
test condition
TRUE
continue
with next
iteration
statement body
end of statement
#include <stdio.h>
void main()
{
int sum = 0, i = 100 ;
while ( i )
sum += i-- ;// note the use of postfix decrement operator!
printf( “Sum is %d \n”, sum ) ;
}
where it should be recalled that any non-zero value is deemed TRUE in the condition section
of the statement.
A for loop is of course the more natural choice where the number of loop iterations is known
beforehand whereas a while loop caters for unexpected situations more easily. For example if
we want to continue reading input from the keyboard until the letter 'Q' is hit we might do the
following.
char ch = '\0' ; /* initialise variable to ensure it is not 'Q' */
while ( ch != 'Q' )
ch = getche() ;
or more succinctly
33 | P a g e
For Example : Program to guess a letter.
#include <stdio.h>
void main()
{
char ch, letter = 'c' ; // secret letter is ‘c’
char finish = ‘\0’ ;
The terminating condition in the for and while loops is always tested before the body of the
loop is executed -- so of course the body of the loop may not be executed at all.
In the do while statement on the other hand the statement body is always executed at least
once as the condition is tested at the end of the body of the loop.
Syntax : do
{
statement body ;
} while ( condition ) ;
34 | P a g e
statement body
continue
with next
iteration
TRUE
test condition
FALSE
end of statement
For Example : To read in a number from the keyboard until a value in the range 1 to 10 is
entered.
int i ;
do
{
scanf( "%d\n", &i ) ;
_flushall() ;
} while ( i < 1 && i > 10 ) ;
In this case we know at least one number is required to be read so the do-while might be the
natural choice over a normal while loop.
The for statement is most often used in situations where the programmer knows in advance
how many times a particular set of statements are to be repeated. The for statement is
sometimes termed a counted loop.
initialisation :- this is usually an assignment to set a loop counter variable for example.
condition :- determines when loop will terminate.
increment :- defines how the loop control variable will change each time the loop is
executed.
statement body :- can be a single statement, no statement or a block of statements.
35 | P a g e
initialisation
FALSE
test condition
TRUE
continue
with next
iteration
statement body
increment
end of statement
The square braces above are to denote optional sections in the syntax but are not part of the
syntax. The semi-colons must be present in the syntax.
#include <stdio.h>
void main()
{
int x ;
Curly braces are used in C to denote code blocks whether in a function as in main() or as the
body of a loop.
For Example :- To print out all numbers from 1 to 100 and calculate their sum.
#include <stdio.h>
void main()
{
int x, sum = 0 ;
36 | P a g e
printf( "%d\n", x ) ;
sum += x ;
}
printf( “\n\nSum is %d\n”, sum ) ;
}
Multiple Initialisations
C has a special operator called the comma operator which allows separate expressions to be
tied together into one statement.
For example it may be tidier to initialise two variables in a for loop as follows :-
Any of the four sections associated with a for loop may be omitted but the semi-colons must
be present always.
For Example :-
for ( x = 0; x < 10; )
printf( "%d\n", x++ ) ;
...
x=0;
for ( ; x < 10; x++ )
printf( "%d\n", x ) ;
for ( ; ; )
statement body ;
Sometimes a for statement may not even have a body to execute as in the following example
where we just want to create a time delay.
37 | P a g e
for ( x = 1; x <= 100; printf( "%d\n", x++ ) ) ;
The initialisation, condition and increment sections of the for statement can contain any valid
C expressions.
for ( x = 12 * 4 ; x < 34 / 2 * 47 ; x += 10 )
printf( “%d “, x ) ;
It is possible to build a nested structure of for loops, for example the following creates a large
time delay using just integer variables.
unsigned int x, y ;
break statement
When a break statement is encountered inside a while, for, do/while or switch statement the
statement is immediately terminated and execution resumes at the next statement following
the statement.
For Example :-
...
38 | P a g e
for ( x = 1 ; x <= 10 ; x++ )
{
if ( x > 4 )
break ;
printf( “%d “ , x ) ;
}
printf( "Next executed\n" );//Output : “1 2 3 4 Next Executed”
...
continue statement
The continue statement terminates the current iteration of a while, for or do/while statement
and resumes execution back at the beginning of the loop body with the next iteration.
For Example :-
...
for ( x = 1; x <= 5; x++ )
{
if ( x == 3 )
continue ;
printf( “%d “, x ) ;
}
printf( “Finished Loop\n” ) ; // Output : “1 2 4 5 Finished Loop”
...
39 | P a g e
UNIT - II
UNIT – II
2.1 ARRAYS
Arrays are widely used data type in ‘C’ language. It is a collection of elements of similar data
type. These similar elements could be of all integers, all floats or all characters. An array of
character is called as string whereas and array of integer or float is simply called as an array.
So array may be defined as a group of elements that share a common name and that are
defined by position or index. The elements of an arrays are store in sequential order in
memory.
There are mainly two types of Arrays are used:
int a[10];
declares an array, named a, consisting of ten elements, each of type int.. (Arrays in
programming are similar to vectors or matrices in mathematics.) Array is represented as
follows:
In C, arrays are zero-based: the ten elements of a 10-element array are numbered from 0 to 9.
The subscript which specifies a single element of an array is simply an integer expression in
square brackets. The first element of the array is a[0], the second element is a[1], etc. You
can use these ``array subscript expressions'' anywhere you can use the name of a simple
variable, for example:
a[0] = 10;
a[1] = 20;
a[2] = a[0] + a[1];
Notice that the subscripted array references (i.e. expressions such as a[0] and a[1]) can appear
on either side of the assignment operator. It is possible to initialize some or all elements of an
array when the array is defined. The syntax looks like this:
40 | P a g e
The list of values, enclosed in braces {}, separated by commas, provides the initial values for
successive elements of the array.
The subscript does not have to be a constant like 0 or 1; it can be any integral expression. For
example, it's common to loop over all elements of an array:
int i;
Arrays are a real convenience for many problems, but there is not a lot that C will do with
them for you automatically. In particular, you can neither set all elements of an array at once
nor assign one array to another; both of the assignments
a = 0; /* WRONG */
and
int b[10];
b = a; /* WRONG */
are illegal.
To set all of the elements of an array to some value, you must do so one by one, as in the loop
example above. To copy the contents of one array to another, you must again do so one by
one:
int b[10];
int a[10];
there is no element a[10]; the topmost element is a[9]. This is one reason that zero-based
loops are also common in C. Note that the for loop
41 | P a g e
loop has i set to 9. (The comparison i <= 9 would also work, but it would be less clear and
therefore poorer style.)
Multidimensional Array
int a2[5][7];
In above declaration, a2 is an array of 5 arrays of 7 ints or, a2 is an array of array of int. You
can think of a2 as having 5 “rows'' and 7 “columns”. (You could also treat the “first'' or inner
subscript as “x” and the second as ”y”.
To illustrate the use of multidimensional arrays, we might fill in the elements of the above
array a2 using this piece of code:
int i, j;
for(i = 0; i < 5; i = i + 1)
{
for(j = 0; j < 7; j = j + 1)
a2[i][j] = 10 * i + j;
}
This pair of nested loops sets a[1][2] to 12, a[4][1] to 41, etc. Since the first dimension of a2
is 5, the first subscripting index variable, i, runs from 0 to 4. Similarly, the second subscript
varies from 0 to 6.
We could print a2 out (in a two-dimensional way, suggesting its structure) with a similar pair
of nested loops:
for (i = 0; i < 5; i = i + 1)
{
for (j = 0; j < 7; j = j + 1)
printf ("%d\t", a2[i][j]);
printf ("\n");
}
Just to see more clearly what's going on, we could make the ``row'' and ``column'' subscripts
explicit by printing them, too:
for(j = 0; j < 7; j = j + 1)
42 | P a g e
printf("\t%d:", j);
printf ("\n");
for(i = 0; i < 5; i = i + 1)
{
printf("%d:", i);
for(j = 0; j < 7; j = j + 1)
printf("\t%d", a2[i][j]);
printf("\n");
}
2.2 FUNCTIONS
Function is a set of statements that are to be executed as a unit in a given order and that can
be referenced by a unique name. The only way to execute these statements is by invoking
them or calling them using the function’s name.
Functions are the highest level of the building blocks given to us in C and correspond to the
sub-tasks or logical units referred to above. The identification of functions in program design
is an important step and will in general be a continuous process subject to modification as
more becomes known about the programming problem in progress.
We have already discussed C functions such as main( ) , printf(), etc. the common trait they
share being the braces that indicate they are C functions.
43 | P a g e
The above is termed the function definition.
Many functions will produce a result or return some information to the point at which it is
called. These functions specify the type of this quantity via the return_type section of the
function definition. If the return type is void it indicates the function returns nothing.
The function_name may be any valid C identifier and must be unique in a particular
program. If a function requires information from the point in the program from which it is
called this may be passed to it by means of the parameter_list. The parameter list must
identify the names and types of all of the parameters to the function individually. If the
function takes no parameters the braces can be left empty or use the keyword void to indicate
that situation more clearly.
Function Prototype
This declaration simply informs the compiler what type the function returns and what type
and how many parameters it takes. Names may or may not be given to the parameters at this
time.
44 | P a g e
Function Definition & Local Variables
A function definition actually defines what the function does and is essentially a discrete
block of code which cannot be accessed by any statement in any other function except by
formally calling the function. Thus any variables declared and used in a function are private
or local to that function and cannot be accessed by any other function.
For Example :-
#include <stdio.h>
void Fun1( void ) ;
void main( )
{
Fun1 () ;
}
void Fun1 ( )
{
int i ; /* local or automatic variable */
for ( i=0; i<10; i++ )
printf( "Hello to Function \n" );
}
The variable i in the Fun1function is private to the Fun1 function i.e. it can only be accessed
by code in the Fun1() function.
Local variables are classified as automatic variables because each time a function is called the
variable is automatically created and is destroyed when the function returns control to the
calling function. By created we mean that memory is set aside to store the variable’s value
and by destroyed we mean that the memory required is released. Thus a local variable cannot
hold a value between consecutive calls to the function.
The keyword static can be used to force a local variable to retain its value between function
calls.
For Example :-
#include <stdio.h>
void hello( void ) ;
void main ()
{
int i ;
45 | P a g e
for ( i = 0; i < 10; i++ )
hello ( ) ;
}
void hello( )
{
static int i = 1 ;
The static int i is created and initialised to 1 when the function is first called, and then
variable retains its last value during subsequent calls to the function and is only destroyed
when the program terminates.
Note: The variables i in main() and i in hello() are completely different variables even
though they have the same name because they are private to the function in which they are
declared. The compiler distinguishes between them by giving them their own unique internal
names.
Returning a Value
The return statement is used to return a value to the calling function if necessary.
If a function has a return type of type void the expression section can be omitted completely
or indeed the whole return statement can be omitted and the closing curly brace of the
function will cause execution to return appropriately to the calling function.
For Example :-
#include <stdio.h>
46 | P a g e
printf( "hello was called %d times\n", i ) ;
return 0 ;
}
int hello( )
{
static int i = 1 ;
printf( "Hello World \n" ) ; // hello() keeps track of how many
times it was called
return ( i++ ) ; // and passes that information back to its
caller
}
Note: The return value of the function need not always be used when calling it. In the above
example if we are not interested in know how often hello() has been called we simply ignore
that information and invoke the function with
hello() ;
The types of all function arguments should be declared in the function prototype as well as in
the function definition.
Note: In C arguments are passed to functions using the call-by-value scheme. This means
that the compiler copies the value of the argument passed by the calling function into the
formal parameter list of the called function. The formal parameters of a function are local
variables of the function and are created upon entry and destroyed on exit.
Example :- Program to add two numbers.
#include <stdio.h>
int add( int, int ) ; /* prototype -- need to indicate types only */
void main ( )
{
int x, y ;
puts ( "Enter two integers ") ;
scanf( "%d %d", &x, &y) ;
printf( "%d + %d = %d\n" , x, y, add(x,y) ) ;
}
int add ( int a, int b )
{
int result ;
result = a + b ;
return result ; // parentheses used for clarity here
}
47 | P a g e
Note: In the formal parameter list of a function the parameters must be individually typed.
The add() function here has three local variables, the two formal parameters and the variable
result. There is no connection between the calling arguments, x and y, and the formal
parameters, a and b, other than that the formal parameters are initialized with the values in the
calling arguments when the function is invoked. The situation is depicted below to emphasize
the independence of the various variables.
main() add()
y Value copied b
#include <stdio.h>
void swap( int, int ) ;
void main( )
{
int a, b ;
48 | P a g e
Since C uses call by value to pass parameters what we have actually done in this program is
to swap the values of the formal parameters but we have not changed the values in main().
Also since we can only return one value via the return statement we must find some other
means to alter the values in the calling function.
The solution is to use call by reference where the addresses of the calling arguments are
passed to the function parameter list and the parameters are pointers which we will encounter
later on. For example when we use the scanf() standard library function to read values from
the keyboard we use the & operator to give the address of the variables into which we want
the values placed.
Storage Classes
There are four storage class modifiers used in C which determine an identifier’s storage
duration and scope.
auto
static
register
extern
An identifier’s storage duration is the period during which that identifier exists in memory.
Some identifiers exist for a short time only, some are repeatedly created and destroyed and
some exist for the entire duration of the program. An identifier’s scope specifies what
sections of code it is accessible from.
The auto storage class is implicitly the default storage class used and simply specifies a
normal local variable which is visible within its own code block only and which is created
and destroyed automatically upon entry and exit respectively from the code block.
The register storage class also specifies a normal local variable but it also requests that the
compiler store a variable so that it may be accessed as quickly as possible, possibly from a
CPU register.
The static storage class causes a local variable to become permanent within its own code
block i.e. it retains its memory space and hence its value between function calls.
When applied to global variables the static modifier causes them to be visible only within the
physical source file that contains them i.e. to have file scope. Whereas the extern modifier
which is the implicit default for global variables enables them to be accessed in more than
one source file.
For example, if two C source code files to be compiled together to give one executable and
where one specific global variable needs to be used by both the extern class allows the
programmer to inform the compiler of the existence of this global variable in both files.
49 | P a g e
2.3 RECURSION
A recursive function is a function that calls itself either directly or indirectly through another
function. Recursive function calling is often the simplest method to eventually simplified into
a series of more basic operations of the same type as the original complex operation.
This is especially true of certain types of mathematical functions. For example to evaluate the
factorial of a number, n
n! = n * (n-1)!
where the original problem has been reduced in complexity slightly. We continue this process
until we get the problem down to a task that may be solved directly, in this case as far as
evaluating the factorial of 1 which is simply 1.
So a recursive function to evaluate the factorial of a number will simply keep calling itself
until the argument is 1. All of the previous (n-1) recursive calls will still be active waiting
until the simplest problem is solved before the more complex intermediate steps can be built
back up giving the final solution.
#include <stdio.h>
short factorial( short ) ;
void main()
{
int i ;
50 | P a g e
This program will not work very well as is because the values of factorials grow very large
very quickly. For example the value of 8! is 40320 which is too large to be held so integer
overflow will occur when the value entered is greater. Can you offer a solution to this ?
In certain situations programs with recursive functions can be slower than those without
because there is a time delay in actually calling the function and passing parameters to it.
There is also a memory penalty involved. If a large number of recursive calls are needed this
means that there are that many functions active at that time which may exhaust the machine’s
memory resources. Each one of these function calls has to maintain its own set of parameters
on the program stack.
Another Example Function to Find GCD of given 2 numbers using Recursive Function
#include <stdio.h>
int GCD ( int, int);
void main()
{
int a, b, c, d, e, result ;
51 | P a g e
break;
case 1:
return(1);
break;
default: /* Including recursive calls */
return(fib(num - 1) + fib(num - 2));
break;
}
}
Both user and system header files are included using the preprocessing directive `#include'. It
has two variants:
#include <file>
This variant is used for system header files. It searches for a file named file in a standard list
of system directories.
#include "file"
This variant is used for header files of your own program. It searches for a file named file
first in the directory containing the current file, then in the quote directories and then the
same directories used for <file>.
The argument of `#include', whether delimited with quote marks or angle brackets, behaves
like a string constant in that comments are not recognized, and macro names are not
expanded. Thus, #include <x/*y> specifies inclusion of a system header file named x/*y.
However, if backslashes occur within file, they are considered ordinary text characters, not
escape characters. None of the character escape sequences appropriate to string constants in C
are processed. Thus, #include "x\n\\y" specifies a filename containing three backslashes.
(Some systems interpret `\' as a pathname separator. All of these also interpret `/' the same
way. It is most portable to use only `/'.)
It is an error if there is anything (other than comments) on the line after the file name.
52 | P a g e
Macro Definitionss (#define)
You create macros with the `#define' directive. `#define' is followed by the name of the
macro and then the token sequence it should be an abbreviation for, which is variously
referred to as the macro's body, expansion or replacement list. For example,
defines a macro named BUFFER_SIZE as an abbreviation for the token 1024. If somewhere
after this `#define' directive there comes a C statement of the form .
then the C preprocessor will recognize and expand the macro BUFFER_SIZE. The C
compiler will see the same tokens as it would if you had written .
By convention, macro names are written in uppercase. Programs are easier to read when it is
possible to tell at a glance which names are macros.
The macro's body ends at the end of the `#define' line. You may continue the definition onto
multiple lines, if necessary, using backslash-newline. When the macro is expanded, however,
it will all come out on one line. For example,
#define NUMBERS 1, \
2, \
3
int x[] = { NUMBERS };
==> int x[] = { 1, 2, 3 };
The most common visible consequence of this is surprising line numbers in error messages.
There is no restriction on what can go in a macro body provided it decomposes into valid
preprocessing tokens. Parentheses need not balance, and the body need not resemble valid C
code. The C preprocessor scans your program sequentially. Macro definitions take effect at
the place you write them. Therefore, the following input to the C preprocessor
foo = X;
#define X 4
bar = X;
53 | P a g e
produces
foo = X;
bar = 4;
When the preprocessor expands a macro name, the macro's expansion replaces the macro
invocation, then the expansion is examined for more macros to expand. For example,
TABLESIZE is expanded first to produce BUFSIZE, then that macro is expanded to produce
the final result, 1024.
Notice that BUFSIZE was not defined when TABLESIZE was defined. The `#define' for
TABLESIZE uses exactly the expansion you specify—in this case, BUFSIZE—and does not
check to see whether it too contains macro names. Only when you use TABLESIZE is the
result of its expansion scanned for more macro names.
This makes a difference if you change the definition of BUFSIZE at some point in the source
file. TABLESIZE, defined as shown, will always expand using the definition of BUFSIZE
that is currently in effect:
Ifdef
If
Defined
Else
Elif
Ifdef
54 | P a g e
#ifdef MACRO
controlled text
#endif /* MACRO */
This block is called a conditional group. controlled text will be included in the output of the
preprocessor if and only if MACRO is defined. We say that the conditional succeeds if
MACRO is defined, fails if it is not.
The controlled text inside of a conditional can include preprocessing directives. They are
executed only if the conditional succeeds. You can nest conditional groups inside other
conditional groups, but they must be completely nested. In other words, `#endif' always
matches the nearest `#ifdef' (or `#ifndef', or `#if'). Also, you cannot start a conditional group
in one file and end it in another.
The comment following the `#endif' is not required, but it is a good practice if there is a lot of
controlled text, because it helps people match the `#endif' to the corresponding `#ifdef'.
Sometimes you wish to use some code if a macro is not defined. You can do this by writing
`#ifndef' instead of `#ifdef'. One common use of `#ifndef' is to include code only the first
time a header file is included.
If
The `#if' directive allows you to test the value of an arithmetic expression, rather than the
mere existence of one macro. Its syntax is
#if expression
controlled text
#endif /* expression */
Integer constants.
Character constants, which are interpreted as they would be in normal code.
Arithmetic operators for addition, subtraction, multiplication, division, bitwise
operations, shifts, comparisons, and logical operations (&& and ||). The latter two
obey the usual short-circuiting rules of standard C.
Macros. All macros in the expression are expanded before actual computation of the
expression's value begins.
Uses of the defined operator, which lets you check whether macros are defined in the
middle of an `#if'.
55 | P a g e
Defined
The special operator defined is used in `#if' and `#elif' expressions to test whether a certain
name is defined as a macro. defined name and defined (name) are both expressions whose
value is 1 if name is defined as a macro at the current point in the program, and 0 otherwise.
Thus, #if defined MACRO is precisely equivalent to #ifdef MACRO.
defined is useful when you wish to test more than one macro for existence at once. For
example,
can generally be simplified to just #if BUFSIZE >= 1024, since if BUFSIZE is not defined,
then it is interpreted as the value zero.
If the defined operator appears as a result of a macro expansion, the C standard says the
behavior is undefined..
Else
The `#else' directive can be added to a conditional to provide alternative text to be used if the
condition fails. This is what it looks like:
#if expression
text-if-true
#else /* Not expression */
text-if-false
#endif /* Not expression */
Elif
One common case of nested conditionals is used to check for more than two possible
alternatives. For example, you might have
56 | P a g e
#if X == 1
...
#else /* X != 1 */
#if X == 2
...
#else /* X != 2 */
...
#endif /* X != 2 */
#endif /* X != 1 */
#if X == 1
...
#elif X == 2
...
#else /* X != 2 and X != 1*/
...
#endif /* X != 2 and X != 1*/
`#elif' stands for “else if”. Like `#else', it goes in the middle of a conditional group and
subdivides it; it does not require a matching `#endif' of its own. Like `#if', the `#elif' directive
includes an expression to be tested. The text following the `#elif' is processed only if the
original `#if'-condition failed and the `#elif' condition succeeds.
More than one `#elif' can go in the same conditional group. Then the text after each `#elif' is
processed only if the `#elif' condition succeeds after the original `#if' and all previous `#elif'
directives within it have failed.
`#else' is allowed after any number of `#elif' directives, but `#elif' may not follow `#else'.
57 | P a g e
UNIT - III
UNIT - III
3.1 POINTERS
A pointer is a variable that is used to store a memory address. Most commonly the address is
the location of another variable in memory. If one variable holds the address of another then
it is said to point to the second variable.
In the above illustration ivar is a variable of type int with a value 23 and stored at memory
location 1012. ivar_ptr is a variable of type pointer to int which has a value of 1012 and is
stored at memory location 1004. Thus ivar_ptr is said to point to the variable ivar and allows
us to refer indirectly to it in memory.
Note : It should be remembered that ivar_ptr is a variable itself with a specific piece of
memory associated with it, in this 32-bit case four bytes at address 1004 which is used to
store an address.
Pointer Variables
Pointers like all other variables in C must be declared as such prior to use.
which indicates that ptr is a pointer to a variable of type type. For example
int *ptr ;
Note: The type of the pointer variable ptr is int *. The declaration of a pointer variable
normally sets aside just two or four bytes of storage for the pointer whatever it is defined to
point to.
In 16-bit systems two byte pointers are termed near pointers and are used in small memory
model programs where all addresses are just segment offset addresses and 16 bits in length.
In larger memory model programs addresses include segment and offset addresses and are 32
58 | P a g e
bits long and thus pointers are 4 bytes in size and are termed far pointers. In 32-bit systems
we have a flat address system where every part of memory is accessible using 32-bit pointers.
& is a unary operator that returns the address of its operand which must be a variable.
For Example :-
int *m ;
int count=125, i ;/* m is a pointer to int, count, i are integers */
m = &count ;
The * operator is the complement of the address operator & and is normally termed the
indirection operator. Like the & operator it is a unary operator and it returns the value of the
variable located at the address its operand stores.
For Example :-
i = *m ;
assigns the value which is located at the memory location whose address is stored in m, to the
integer i. So essentially in this case we have assigned the value of the variable count to the
variable i. The final situation is illustrated below.
indirection
count i m
125 125 1000
1000 1724 1824
One of the most frequent causes of error when dealing with pointers is using an un-initialized
pointer. Pointers should be initialized when they are declared or in an assignment statement.
Like any variable if you do not specifically assign a value to a pointer variable it may contain
any value. This is extremely dangerous when dealing with pointers because the pointer may
point to any arbitrary location in memory, possibly to an unused location but also possibly to
a memory location that is used by the operating system. If your program tries to change the
value at this address it may cause the whole system to crash. Therefore it is important to
59 | P a g e
initialise all pointers before use either explicitly in your program or when defining the
pointer.
A pointer may also be initialised to 0 ( zero ) or NULL which means it is pointing at nothing.
This will cause a run-time error if the pointer is inadvertently used in this state. It is useful to
be able to test if a pointer has a null value or not as a means of determining if it is pointing at
something useful in a program.
Note: NULL is #defined in <stdio.h>.
For Example :-
int var1, var2 ;
int *ptr1, *ptr2 = &var2 ;
int *ptr3 = NULL ;
...
ptr1 = &var1 ;
ptr1 and ptr2 are now pointing to data locations within the program.
Call by Reference
Recall when we wanted to swap two values using a function we were unable to actually swap
the calling parameters as the call by value standard was employed. The solution to the
problem is to use call by reference which is implemented in C by using pointers as is
illustrated in the following example.
#include <stdio.h>
void swap( int *, int * ) ;
void main( )
{
int a, b ;
printf( "Enter two numbers" ) ;
scanf( " %d %d ", &a, &b ) ;
printf( "a = %d ; b = %d \n", a, b ) ;
swap( &a, &b ) ;
printf( "a = %d ; b = %d \n", a, b ) ;
}
void swap ( int *x, int *y )
{
int t ;
t = *x ;
*x = *y ;
*y = t ;
}
60 | P a g e
The swap() function is now written to take integer pointers as parameters and so is called in
main() as
swap( &a, &b ) ;
where the addresses of the variables are passed and copied into the pointer variables in the
parameter list of swap(). These pointers must be de-referenced to manipulate the values, and
it is values in the same memory locations as in main() we are swapping unlike the previous
version of swap where we were only swapping local data values.
In our earlier call-by-value version of the program we called the function from main() as
swap(a,b); and the values of these two calling arguments were copied into the formal
arguments of function swap.
In our call-by-reference version, formal arguments are pointers to int and it is the addresses
contained in these pointers, (i.e. the pointer values), that are copied here into the formal
arguments of the function. However when we de-reference these pointers we are accessing
the values in the main() function as their addresses do not change.
There is a very close relationship between pointer and arrays in C. As we have seen already
the name of an array ( or string ) is actually the address in memory of the array and so it is
essentially a constant pointer.
For Example :-
char str[80], *ptr ;
ptr = str ;/* causes ptr to point to start of string str */
ptr = &str[0] ; /* this performs the same as above */
Instead of using the normal method of accessing array elements using an index we can
use pointers in much the same way to access them as follows.
Note that the parentheses are necessary above as the precedence of * is higher than that of +.
The expression
61 | P a g e
ch = *ptr + 1 ;
For example says to access the character pointed to by ptr ( str[0] in above example with
value ‘a’) and to add the value 1 to it. This causes the ASCII value of ‘a’ to be incremented
by 1 so that the value assigned to the variable ch is ‘b’.
Pointer Arithmetic
Pointer variables can be manipulated in certain limited ways. Many of the manipulations are
most useful when dealing with arrays which are stored in contiguous memory locations.
Knowing the layout of memory enables us to traverse it using a pointer.
Assignment
int count, *p1, *p2 ;
p1 = &count ; // assign the address of a variable directly
p2 = p1 ; // assign the value of another pointer variable, an address
Addition / Subtraction
The value a pointer holds is just the address of a variable in memory, which is normally a
four byte entity. It is possible to modify this address by integer addition and subtraction if
necessary. Consider the following we assume a 32-bit system and hence 32-bit integers.
We now have the pointer variable ptr pointing at the start of array which is stored at memory
location 2008 in our illustration. Since we know that element array[1] is stored at address
2012 directly after element array[0] we could perform the following to access its value using
the pointer.
ptr += 1 ;
This surprisingly will cause ptr to hold the value 1012 which is the address of array[1], so we
can access the value of element array[1]. The reason for this is that ptr is defined to be a
pointer to type int, which are four bytes in size on a 32-bit system. When we add 1 to ptr what
62 | P a g e
we want to happen is to point to the next integer in memory. Since an integer requires four
bytes of storage the compiler increments ptr by 4. Likewise a pointer to type char would be
incremented by 1, a pointer to float by 4, etc.
Similarly we can carry out integer subtraction to move the pointer backwards in memory.
ptr = ptr - 1 ;
ptr -= 10 ;
The shorthand operators ++ and -- can also be used with pointers. In our continuing example
with integers the statement ptr++ ; will cause the address in ptr to be incremented by 4 and
so point to the next integer in memory and similarly ptr-- ; will cause the address in ptr to be
decremented by 4 and point to the previous integer in memory.
Note: Two pointer variables may not be added together ( it does not make any logical sense ).
count = p2 - p1 ; /* legal */
The result of such an operation is not however a pointer, it is the number of elements of the
base type of the pointer that lie between the two pointers in memory.
Comparisons
We can compare pointers using the relational operators ==, <, and > to establish whether
two pointers point to the same location, to a lower location in memory, or to a higher location
in memory.
1. Using array notation
void puts( const char s[ ] ) /* const keyword makes string contents read only */
{
int i ;
for ( i = 0; s[i] ; i++ )
putchar( s[i] ) ;
putchar( '\n' ) ;
}
63 | P a g e
void puts( const char *s ) // char *const s would make pointer unalterable
{
while ( *s )
putchar( *s++ ) ;
putchar( '\n' ) ;
}
#include <stdio.h>
int palin( char * ) ; /* Function to determine if array is a palindrome. returns 1 if
it is a palindrome, 0 otherwise */
void main( )
{
char str[30], c ;
if ( palin( str ) )
printf( "%s is a palindrome\n", str ) ;
else
printf( "%s is not a palindrome\n") ;
}
ptr = str ;
while ( *ptr )
ptr++ ; /* get length of string i.e. increment ptr while *ptr != '\0' */
ptr-- ; /* move back one from '\0' */
64 | P a g e
Strings and pointers
C's standard library string handling functions use pointers to manipulate the strings. For
example the prototype for the strcmp() function found in <string.h> is
where const is a C keyword which locks the variable it is associated with and prevents any
inadvertent changes to it within the function.
in both cases the compiler allocates just sufficient storage for both strings.
The name of an array without any index is the address of the first element of the array and
hence of the whole array as it is stored contiguously. However we need to know the size of
the array in the function - either by passing an extra parameter or by using the sizeof operator.
For Example :-
void main()
{
int array[20] ;
func1( array ) ;/* passes pointer to array to func1 */
}
Since we are passing the address of the array the function will be able to manipulate the
actual data of the array in main(). This is call by reference as we are not making a copy of the
data but are instead passing its address to the function. Thus the called function is
manipulating the same data space as the calling function.
65 | P a g e
main() func1
refers to data
array x
at address 1000
data at
no data here
address 1000
In the function receiving the array the formal parameters can be declared in one of three
almost equivalent ways as follows :
As a sized array :
func1 ( int x[10] ) {
...
}
As an unsized array :
func1 ( int x[ ] ) {
...
}
As an actual pointer
func1 ( int *x ) {
...
}
All three methods are identical because each tells us that in this case the address of an array
of integers is to be expected.
Note however that in cases 2 and 3 above where we specify the formal parameter as an
unsized array or simply as a pointer we cannot determine the size of the array passed in using
the sizeof operator as the compiler does not know what dimensions the array has at this point.
Instead sizeof returns the size of the pointer itself, two in the case of near pointers in a 16-bit
system but four in 32-bit systems.
#include <stdio.h>
void read_array( double array[ ], int size ) ;
double mean( double array[ ], int size ) ;
void main()
{
double data[ 100 ] ;
66 | P a g e
double average ;
#include <stdio.h>
int palin( char array[ ] ) ; /* Function to determine if array
is a palindrome returns 1 if it is a palindrome, 0 otherwise */
void main( )
{
char str[100] ;
if ( palin( str ) )
printf( "%s is a palindrome\n", str ) ;
else
printf( "%s is not a palindrome\n") ;
}
67 | P a g e
int palin ( char array[ ] )
{
int i = 0, j = 0 ;
while ( array[j++] ) ; /* get length of string i.e. increment j while array[j] != '\0' */
j -= 2 ; /* move back two -- gone one beyond '\0' */
An alternative way of writing the palin() function might be as follows using string
manipulation functions ( must add #include <string.h> to top of file in this case).
Function calls with multi-dimensional arrays will be the same as with single dimension arrays
as we will still only pass the address of the first element of the array.
However to declare the formal parameters to the function we need to specify all but one of
the dimensions of the array so that it may be indexed properly in the function.
For Example :-
68 | P a g e
Call func1 with x a parameter :- func1( x ) ;
The compiler must at least be informed how many columns the matrix has to index it
correctly. For example to access element y[5][3] of the array in memory the compiler might
do the following
element No = 5 * 20 + 3 = 103.
NB : Multi-dimensional arrays are stored row-wise so y[5][3] is the 4th element in the 6th row.
Since we are dealing with an array of doubles this means it must access the memory location
103 X 8 bytes from the beginning of the array.
Thus the compiler needs to know how many elements are in each row of the 2D array above.
In general the compiler needs to know all dimensions except the leftmost at the very least.
void mat_read( int mat[2][2] ) ; // Write these two functions on your own
void mat_print( int mat[2][2] ) ;
void mat_add( int mat1[ ][2], int mat2[ ][2], int mat3[ ][2] ) ;
void main()
{
int mat_a[2][2], mat_b[2][2], mat_res[2][2] ;
69 | P a g e
puts( “The resultant matrix is\n” ) ;
mat_print( mat_res ) ;
}
void mat_add( int mat1[ ][2], int mat2[ ][2], int mat3[ ][2] )
{
int j, k ;
This is the means by which a program can obtain and release memory at run-time. This is
very important in the case of programs which use large data items e.g. databases which may
need to allocate variable amounts of memory or which might have finished with a particular
data block and want to release the memory used to store it for other uses.
The functions malloc() and free() form the core of C's dynamic memory allocation and are
prototyped in <malloc.h>. malloc() allocates memory from the heap i.e. unused memory
while available and free() releases memory back to the heap.
malloc() allocates num_bytes bytes of storage and returns a pointer to type void to the block
of memory if successful, which can be cast to whatever type is required. If malloc() is unable
to allocate the requested amount of memory it returns a NULL pointer.
For example to allocate memory for 100 characters we might do the following
#include <malloc.h>
void main()
{
char *p ;
70 | P a g e
The return type void * is automatically cast to the type of the lvalue type but to make it more
explicit we would do the following
free ( p ) ;
Note :- There are a number of memory allocation functions included in the standard library
including calloc( ), _fmalloc( ) etc. Care must be taken to ensure that memory allocated with
a particular allocation function is released with its appropriate deallocation function, e.g.
memory allocated with malloc() is freed only with free() .
Array of Pointers
It is possible to declare arrays of pointers in C the same as any other 'type'. For example
int *x[10] ;
To make one of the pointers point to a variable one might do the following.
x[ 2 ] = &var ;
*x[ 2 ]
Passing this array to a function can be done by treating it the same as a normal array which
happens to be an array of elements of type int *.
For Example : -
void display( int *q[ ], int size )
{
int t ;
71 | P a g e
for ( t=0; t < size; t++ )
printf( "%d ", *q[t] ) ;
}
Note that q is actually a pointer to an array of pointers as we will see later on with multiple
indirection.
puts( err[num] );
}
Note that using an array of pointers to char initialised as above conserves space as no blank
filling characters are required as would be if we used
char err[3][30] = {
... } ;
3.2 STRINGS
Thus the string or character array must always be defined to be one character longer than is
needed in order to cater for the '\0'.
char s[6] ;
'\0'
A string constant is simply a list of characters within double quotes e.g. "Hello" with the '\0'
character being automatically appended at the end by the compiler.
72 | P a g e
A string may be initialized as simply as follows
as opposed to
char s[6] = { 'H', 'e', 'l', 'l', 'o', '\0' } ;
Again the size specification may be omitted allowing the compiler to determine the size
required.
We can print out the contents of a string using printf() as we have seen already or by using
puts().
printf( "%s", s ) ;
puts( s ) ;
scanf( "%s", s ) ;
where we do not require the familiar & as the name of an array without any index or square
braces is also the address of the array.
gets ( s ) ;
Arrays of Strings
An array of strings is in fact a two dimensional array of characters but it is more useful to
view this as an array of individual single dimension character arrays or strings.
For Example :-
char str_array[ 10 ] [ 30 ] ;
where the row index is used to access the individual row strings and where the column index
is the size of each string, thus str_array is an array of 10 strings each with a maximum size of
29 characters leaving one extra for the terminating null character.
73 | P a g e
For Example :- Program to read strings into str_array and print them out character by
character.
#include <stdio.h>
char str_array[10][30] ;
void main()
{
int i, j ;
There are some common inbuilt functions to manipulation on string in string.h file. these are
as follows:
For Example :-
char s1[20] = “String1”, s2[20] = “String2” ;
74 | P a g e
int i ;
C makes use of the typedef keyword to allow new data type names to be defined. No new
type is created, an existing type will now simply be recognised by another name as well. The
existing type can be one of the in-built types or a user-defined type.
where type is C data type and name is the new name for this type.
For Example :-
typedef int INTEGER ;
INTEGER i ; // can now declare a variable of type ‘INTEGER’
The use of typedef makes program code easier to read and when used intelligently can
facilitate the porting of code to a different platform and the modification of code. For
example in a first attempt at a particular program we might decide that floating point
variables will fill our needs. This problem is trivial if we had used a typedef as follows :-
75 | P a g e
typedef double FLOATING;
An enumeration is a user defined data type whose values consist of a set of named integer
constants, and are used for the sole purpose of making program code more readable.
where tag is the name of the enumeration type, value_list is a list of valid values for the
enumeration, and where enum_var is an actual variable of this type.
For Example :-
enum colours { red, green, blue, orange } shade ;
// values red - 0, green - 1, blue - 2, orange - 3
enum day { sun = 1, mon, tue, wed = 21, thur, fri, sat } ;
enum day weekday ;
// values are 1, 2, 3, 21, 22, 23, 24
Variables declared as enumerated types are treated exactly as normal variables in use and are
converted to integers in any expressions in which they are used.
For Example :-
int i ;
color a,b;
a=RED;
a = RED+BLUE; //NOT ALLOWED in C
if ((a == BLUE) || (a==b)) cout<<"great";
Notice that an enumerated type is a code that associates symbols and numbers. The char type
can be thought of as an enumeration of character codes. The default code for an enumerated
76 | P a g e
type assigns the first name to the value 0 (RED), second name 1 (BLUE), third 2 (GREEN)
etc. The user can, however, override any, or all, of the default codes by specifying alternative
values.
77 | P a g e
UNIT - IV
UNIT- IV
4.1 STRUCTURES
A structure is a user defined data type in C/C++. A structure creates a data type that can be
used to group items of possibly different types into a single type.
Structures are used to represent a record. Suppose you want to keep track of your books in a
library.
You might want to track the following attributes about each book −
Title
Author
Subject
Book ID
78 | P a g e
{
int x, y;
};
int main()
{
// A valid initialization. member x gets value 0 and y
// gets value 1. The order of declaration is followed.
struct Point p1 = {0, 1};
}
Structure members cannot be initialized with declaration. For example the following C
program fails in compilation.
struct Point
{
int x = 0; // COMPILER ERROR: cannot initialize members here
int y = 0; // COMPILER ERROR: cannot initialize members here
};
The reason for above error is simple, when a datatype is declared, no memory is allocated for
it. Memory is allocated only when variables are created.
ACCESSING STRUCTURES
Structure members are accessed using dot (.) operator.
struct Point
{
int x, y;
};
int main()
{
struct Point p1 = {0, 1};
// Accesing members of point p1
p1.x = 20;
printf ("x = %d, y = %d", p1.x, p1.y);
return 0;
}
4.2 NESTED STRUCTURES
A structure can be nested inside another structure. In other words, the members of a structure
can be of any other type including structure.
structure tagname_1
{
member1;
member2;
member3;
...
member n;
structure tagname_2
79 | P a g e
{
member_1;
member_2;
member_3;
...
member_n;
}, var1
} var2;
80 | P a g e
PASSING STRUCTURE TO FUNCTION IN C:
It can be done in below 3 ways:
1. Passing structure to a function by value
#include <stdio.h>
#include <string.h>
struct student
{
int id;
char name[20];
float percentage;
};
int main()
{
struct student record;
record.id=1;
strcpy(record.name, "Raju");
record.percentage = 86.5;
func(record);
return 0;
}
OUTPUT:
Id is: 1
Name is: Raju
Percentage is: 86.500000
81 | P a g e
2. Passing structure to a function by address(reference)
In this program, the whole structure is passed to another function by address.
It means only the address of the structure is passed to another function. The
whole structure is not passed to another function with all members and their
values. So, this structure can be accessed from called function by its address.
#include <stdio.h>
#include <string.h>
struct student
{
int id;
char name[20];
float percentage;
};
int main()
{
struct student record;
record.id=1;
strcpy(record.name, "Raju");
record.percentage = 86.5;
func(&record);
return 0;
}
82 | P a g e
3. No need to pass a structure – Declare structure variable as global
#include <stdio.h>
#include <string.h>
struct student
{
int id;
char name[20];
float percentage;
};
struct student record; // Global declaration of structure
void structure_demo();
int main()
{
record.id=1;
strcpy(record.name, "Raju");
record.percentage = 86.5;
structure_demo();
return 0;
}
void structure_demo()
{
printf(" Id is: %d \n", record.id);
printf(" Name is: %s \n", record.name);
printf(" Percentage is: %f \n", record.percentage);
}
OUTPUT:
Id is: 1
Name is: Raju
Percentage is: 86.500000
83 | P a g e
{
int x, y;
};
int main()
{
struct Point p1 = {1, 2};
// p2 is a pointer to structure p1
struct Point *p2 = &p1;
// Accessing structure members using structure pointer
printf("%d %d", p2->x, p2->y);
return 0;
}
Output: 1 2
Self Referential structures are those structures that have one or more pointers which point to
the same type of structure, as their member.
In other words, structures pointing to the same type of structures are self-referential in nature.
Example:
struct node {
int data1;
char data2;
struct node* link;
};
int main()
{
struct node ob;
return 0;
}
In the above example ‘link’ is a pointer to a structure of type ‘node’. Hence, the structure
‘node’ is a self-referential structure with ‘link’ as the referencing pointer.
An important point to consider is that the pointer should be initialized properly before
accessing, as by default it contains garbage value.
4.7 UNIONS
Unions are quite similar to the structures in C. Union is also a derived type as structure.
Union can be defined in same manner as structures just the keyword 'union' is used in
defining union and the keyword used in defining structure was 'struct'.
84 | P a g e
Union variables can be created in similar manner as structure variable
In both cases, union variables car1, car2 and union pointer variable car3 of type union car is
created.
85 | P a g e
Likewise, if you want to access price for the union pointer variable car3, it can be accessed
as:
Input to a program, means to feed some data into a program. An input can be given in the
form of a file or from the command line. C programming provides a set of built-in functions
to read the given input and feed it to the program as per requirement.
Output of a program, means to display some data on screen, printer, or in any file. C
programming provides a set of built-in functions to output the data on the computer screen as
well as to save it in text or binary files
FILES
A file represents a sequence of bytes, regardless of it being a text file or a binary file.
C programming language provides access on high level functions as well as low level (OS
level) calls to handle file on your storage devices.
Files are divided into two types
1. Stream-oriented – they are standard or high-level files. They are easier to work with than
the sytem-oriented data-files and are used more commonly.
2. System-oriented – they are low-level files.
Opening a file
Before opening any file, a file pointer needs to be established.
Where,
FILE is the structure which is defined in the header file <stdio.h>.
A file should be opened before any operation is being performed on it.
The fopen() function is being used for opening the file.
Syntax:
FILE *fopen(const char *filename, const char *mode);
In the above syntax, filename is the literal which is used for naming the files.
They can be accessed by using the following modes:
86 | P a g e
Closing a file
The fclose() function is used for closing a file.
When this function is used the file pointer is disconnected from a file.
Syntax:
int fclose(FILE *fp);
Where,fp is the file pointer that points to the file that has to be closed. An integer value is
returned which will indicate if the function was successful or not.
In addition to the fclose() function we even have the fcloseall() function which will close all
the streams which are open currently except the standard streams (stdin, stdout and stderr).
Syntax:
intfcloseall(void);
This function will flush any of the stream buffers and will return the number of streams
which are closed.
Reading a file
Following are the list of functions which are used for reading a file:
Writing a file
Following are the list of functions which are used for writing a file:
87 | P a g e
Error handling in file operations
The function ferror() is used for checking the errors in the stream.
Syntax:
int ferror(FILE *stream);
This function returns 0 if there are no errors and a value if there are some errors.
Following are the functions which are used for detecting the errors:
Removing a file
The remove() function is used for erasing a file.
Syntax:
int remove (const char *filename);
All the files which are specified by the filename will be erased.
If this function is successful it will return a zero else it will return a value other than zero.
Renaming the file
The rename() function is used for renaming a file.
Syntax:
int rename(const char *oldname, const char *newname);
88 | P a g e
Where,oldname will be the pathname of the file that needs to be renamed.newname will be
the new pathname of the file.
If this function is successful it will return a zero else it will return a value other than zero.If
an error occurs neither the oldfile name nor the newfile name are renamed or changed.
STREAMS
In C, the stream is a common, logical interface to the various devices that comprise the
computer.
In its most common form, a stream is a logical interface to a file. As C defines the term "file",
it can refer to a disk file, the screen, the keyboard, a port, a file on tape, and so on. Although
files differ in form and capabilities, all streams are the same.
The stream provides a consistent interface and to the programmer one hardware device will
look much like another.
A sequence of bytes flowing into program is called input stream
A sequence of bytes flowing out of the program is called output stream
Use of Stream make I/O machine independent.
Predefined/standard streams in c are the following:
Standard Input(stdin)
Standard output(stdout)
Standard error(stderr)
When the main function of your program is invoked, it already has three predefined streams
open and available for use. These represent the “standard” input and output channels that
have been established for the process.
The standard input stream, which is the normal source of input for the program.
The standard output stream, which is used for normal output from the program.
The standard error stream, which is used for error messages and diagnostics issued
by the program.
89 | P a g e
4.8 STANDARD LIBRARY INPUT OUTPUT FUNCTIONS
90 | P a g e
Close File - fclose
91 | P a g e
Write Character to File - putc, fputc and putchar
92 | P a g e
Write String to File - fputs and puts
size_t fwrite(const void *ptr, size_t siz, size_t num, FILE *stream)
o fwrite writes up to num objects, each siz bytes long, from the memory pointed
to by ptr to the output stream stream.
o The number of objects written is returned.
o If an error occurs, zero will be returned.
93 | P a g e
o fprintf writes to output stream stream.
o sprintf "writes" its output to the character string str (followed by a terminating
'\0'.)
All three functions return the number of characters written (not including the terminating '\0'
for sprintf)
94 | P a g e
Alter File Buffer Size - setbuf and setvbuf
FILE *tmpfile(void)
tmpfile attempts to create a new file and open it using mode wb+.
If the create and open succeed, a FILE pointer is returned.
If the file could not be opened, NULL is returned.
The file is automatically deleted when it is closed or when the process
terminates.
Note that this function may create a file which is publicly readable and
writable.
char *tmpnam(char *str)
tmpnam generates a temporary file name which was not in use when tmpnam
was called.
If str is non-null, the file name is copied to that buffer. str is expected to be at
least L_tmpnam characters long.
If str is null, a static buffer is used, meaning that subsequent calls to tmpnam
may overwrite the buffer.
Temporary file names use the path prefix P_tmpdir.
Both L_tmpnam and P_tmpdir are defined in <stdio.h>.
95 | P a g e
tmpnam is guaranteed to be able to generate at least TMP_MAX unique
temporary file names, where TMP_MAX must be at least 25.
Note that there is a race condition between file name selection and file
creation.
Note also that tmpnam does not create the file and therefore does not ensure
the file will be deleted after the program is terminated.
The basic input/output functions are getchar, putchar, puts, scanf and printf.
The first two functions, getchar and putchar, are used to transfer single characters.
The next function puts is used to output strings, and the last two functions, scanf and printf,
permit the transfer of single characters, numerical values and strings.
The scanf function is used to read formatted input data. The format in which input data is to
be provided is specified by the scanf function itself as it's first parameter. The scanf function
is written as -
scanf(<control string>, &address1, &address2, . . . , &addressn);
Here, the first parameter <control string> contains a list of format specifiers indicating the
format and type of data to be read. The remaining parameters - &address1, &address2, ...,
&addressn are addresses of the variables where the read data will be stored. scanf reads the
96 | P a g e
input data as per the format specifiers and stores them (i.e., assigns them) to the
corresponding addresses. An & is pre-fixed to the variable name to denote its address.
Note that there must be the same number of format specifiers and addresses as there are input
data. For instance, in the following example:
scanf("%d %f",&x,&y);
printf()
The printf function is used to output data onto the standard output device. In general, the
printf function is written as
printf(<control string>, arg1, arg2, . . . , argn);
where the <control string> refers to a string containing required formatting information as in
scanf, and arg1, arg2, ..., argn are individual data variables whose values are to be printed.
However, unlike scanf, these data variable names are not preceded by the & symbol. This is
because printf is expected to only output the values of these variables and not their addresses.
97 | P a g e
UNIT - V
UNIT V
Primitive Data Structures are the basic data structures that directly operate upon the
machine instructions. For example integers, floating point numbers, character constants,
string constants and pointers are the primitive data structures.
Non-primitive data structures are more complicated data structures and are derived from
primitive data structures. They emphasize on grouping same or different data items with
relationship between each data item. Arrays, lists and files are examples of this type.
98 | P a g e
5..2 LINEAR LIST
One of the most simple and most used ADT is the linear list. A linear list is asequence
of n ≥ 0 elements X1,Xn called nodes having the same base type T.
The essential structural properties of a linear list are:
o If n>0 then X1 is the first node and Xn is the last node.
o If 1 < i < n then the i-th node Xi is preceded by Xi-1 and succeeded by Xi+1.
This property expresses the basis of sequential access, i.e. if we know the
current node then we can access its predecessor and its successor.
To define lists as an ADT we must define a set of operators. Note that each set of
operators defines a distinct ADT.
INSERTION
Insertion into a singly-linked list has three cases:
Inserting a new node before the head (at the beginning)
In this case, a new node is inserted before the current head node. Only one next
pointer needs tobe modified (new node’s next pointer) and it can be done in two steps:
o Update the next pointer of new node, to point to the current head.
o Update head pointer to point to the new node.
99 | P a g e
Inserting a new node after the tail (at the end of the list)
In this case, we need to modify two next pointers (last nodes next pointer and new
nodes nextpointer).
o New nodes next pointer points to NULL.
100 | P a g e
o If we want to add an element at position 3 then we stop at position 2.
That means we traverse 2 nodes and insert the new node. For
simplicity let us assume that the second node is called position node.
The new node points to the next node of the position where we want to
add this node.
DELETION
First node (current head node) is removed from the list. It can be done in two steps:
o Create a temporary node which will point to the same node as that of head.
101 | P a g e
o Now, move the head nodes pointer to the next node and dispose of the
temporary node.
In this case, the last node is removed from the list. This operation is a bit trickier than
removing the first node, because the algorithm should find a node, which is previous to the
tail. It can be done in three steps:
o Traverse the list and while traversing maintain the previous node address also.
Bythe time we reach the end of the list, we will have two pointers, one
pointing to the tail node and the other pointing to the node before the tail node.
102 | P a g e
o Dispose of the tail node.
In this case, the node to be removed is always located between two nodes. Head and tail links
are not updated in this case. Such a removal can be done in two steps:
o Similar to the previous case, maintain the previous node while traversing the
list.Once we find the node to be deleted, change the previous node’s next
pointer to the next pointer of the node to be deleted.
In order to search through the list (to find a piece of data, or an insertion point for some new
data), the only option is to traverse through the data one by one, from the start. This is known
as a linear search. More efficient search techniques (such as the binary search) cannot be
performed, as the link structure between data forces sequential access.
103 | P a g e
The step-by-step algorithm to search is, starting at the first data node, and comparing the
search key with the corresponding data in the node:
1 If the data matches, the search is complete.
2 If there is no match, move to the next node and repeat;
3 If the next reference is null, the end of the list has been reached; therefore, the data
does not exist in the list. The algorithm can now terminate
5.3 STACKS
Stack is a linear data structure which follows a particular order in which the operations are
performed. The order may be LIFO (Last In First Out) or FILO (First In Last Out).
OPERATIONS
Mainly the following basic operations are performed in the stack:
Push: Adds an item in the stack. If the stack is full, then it is said to be an Overflow
condition.
Pop: Removes an item from the stack. The items are popped in the reversed order in
which they are pushed. If the stack is empty, then it is said to be an Underflow
condition.
Top: Returns top element of stack.
isEmpty: Returns true if stack is empty, else false.
104 | P a g e
The array storing the stack elements may become full. A push operation will then throw a full
stack exception. Similarly, if we try deleting an element from an empty stack it will throw
stack empty exception.
105 | P a g e
The other way of implementing stacks is by using Linked lists. Push operation is
implemented by inserting element at the beginning of the list. Pop operation is implemented
by deleting the node from the beginning (the header/top node).
106 | P a g e
5.5 STACK APPLICATION
Balancing of symbols
Infix to Postfix /Prefix conversion
Redo-undo features at many places like editors, photoshop.
Forward and backward feature in web browsers
Used in many algorithms like Tower of Hanoi, tree traversals, stock span problem,
histogram problem.
Other applications can be Backtracking, Knight tour problem, rat in a maze, N queen
problem and sudoku solver
In Graph Algorithms like Topological Sorting and Strongly Connected Components
Postfix: A postfix expression (also called Reverse Polish Notation) is a single letter or
an operator, preceded by two postfix strings. Every postfix string longer than a single
variable contains first and second operands followed by an operator.
107 | P a g e
In infix expressions, the operator precedence is implicit unless we use parentheses. Therefore,
for the infix to postfix conversion algorithm we have to define the operator precedence (or
priority) inside the algorithm.
The table shows the precedence and their associativity (order of evaluation) among operators.
108 | P a g e
operator to the stack. (If you encounter parenthesis while popping then stop there and
push the scanned operator in the stack.)
4. If the scanned character is an ‘(‘, push it to the stack.
5. If the scanned character is an ‘)’, pop the stack and and output it until a ‘(‘ is
encountered, and discard both the parenthesis.
6. Repeat steps 2-6 until infix expression is scanned.
7. Print the output
8. Pop and output from the stack until it is not empty.
109 | P a g e
The next character scanned is “*”, which is an operator. Thus, we pop the top two elements
from the stack and perform the “*” operation with the two operands. The second operand will
be the first element that is popped.
The value of the expression (2*3) that has been evaluated (6) is pushed into the stack.
The next character scanned is “+”, which is an operator. Thus, we pop the top two elements
from the stack and perform the “+” operation with the two operands. The second operand will
be the first element that is popped.
110 | P a g e
The value of the expression (1+6) that has been evaluated (7) is pushed into the stack.
111 | P a g e
The next character scanned is “-”, which is an operator. Thus, we pop the top two elements
from the stack and perform the “-” operation with the two operands. The second operand will
be the first element that is popped.
The value of the expression(7-5) that has been evaluated(23) is pushed into the stack.
Now, since all the characters are scanned, the remaining element in the stack (there will be
only one element in the stack) will be returned. End result:
• Postfix String : 123*+5-
• Result : 2
112 | P a g e
Lets use factorial as an example. 5 factorial is 5x4x3x2x1 = 120 and this can be implemented
recursively.
int f(int x){
void main(){
}
So lets watch the stack and see what happens.
main calls the function f with a value of 5, so on the stack we get f(5). Line 1 is false so we
go to line 2 which calls f(4), etc. Note that f(4) must complete before f(5) can complete. f(5)
will complete by returning 5*f(4). The stack will look like:
113 | P a g e
So at this point none of the functions have yet returned! The first to return will be f(1) which
will return 1. Then f(2) will return 2. Then f(3) will return 6. As in:
114 | P a g e
5.6 QUEUES
Queues are data structures that follow the First In First Out (FIFO) i.e. the first element that is
added to the queue is the first one to be removed.
Elements are always added to the back and removed from the front.
A waiting line is a good real-life example of a queue.
OPERATIONS
115 | P a g e
ARRAY AND LINKED REPRESENTATION OF QUEUE
In the array, we add elements circularly and use two variables to keep track of the start
element and end element. Generally, front is used to indicate the start element and rear is
used to indicate the end element in the queue. The array storing the queue elements may
become full. An EnQueue operation will then throw a full queue exception. Similarly, if we
try deleting an element from an empty queue it will throw empty queue exception.
116 | P a g e
Another way of implementing queues is by using Linked lists. EnQueue operation is
implemented by inserting an element at the end of the list. DeQueue operation is
implemented by deleting an element from the beginning of the list.
117 | P a g e
118 | P a g e
119 | P a g e