You are on page 1of 48

Programming in C

Introduction:
Dennis Ritchie developed the C language at Bell Laboratories in the early 1970s. C is
a general-purpose, structured programming language. Its instructions consist of terms
that resemble algebraic expressions augmented by certain English keywords. C also
contains certain additional features, however, that allow it to be used at a lower level,
thus bridging the gap between machine language and more conventional high-level
languages. This flexibility allows C to be used for system programming as well as for
applications programming.
Features of C:
C is a structured programming language.
It is a middle level language.
It is rich in operators and data types.
It optimizes the usage of Memory.
C is simple, contained, versatile and more expressive.
C programs are fast and efficient.
C permits all data conversion and mixed mode operation.
C is proved to be excellent and efficient for a variety of programming applications such
as scientific and commercial quality software developments etc.,
The character set in C:
Alphabet:
A to Z
a to z
Digits:
0 to 9
Special characters:
+-*/=%&#!?^~\|<>()[]{}:;,._
Identifiers:
Identifiers are names that are given to various program elements. Identifiers consist of letters
and digits in any order, except the first character should be a letter.
Keywords:
There are certain reserved words, called keywords that have standard, pre-defined meaning in C.
These keywords can be used only for their intended purpose, they cannot be used as
programmer-defined identifiers. E.g., auto, break, case, char, do, else, if, for..
Variable:
A Variable is an identifier that is used to represent some specified type of information within a
designated portion of a program.
Constants:
A constant refers to fixed value that doesnt change during the execution of program.
There are different types of constants
Integer constants (Constant value without fractional part). e.g. 87 90 3.
Floating points (Constant value with fractional part)
Character constants (Single character enclosed in apostrophes). e.g., v c.
String constants (Constants of any number of consecutive characters enclosed in double
quotation marks). E.g., Computec Bangalore

Data types:
C supports several different types of data, each of which may be represented differently within
the computers memory. The memory requirements for each data type will determine the
permissible range of values for that data type.
Data type
Description
Memory
Representation
Requirements
char
int
float
double

single character
integer quality
floating point
double precision
floating point number

1 byte
2 bytes
4 bytes

c
d
f

8 bytes

C Operators:
An operator is a symbol used to manipulate the data. C has a very rich set of built-in Operators.
Arithmetic Operators:
Arithmetic Operators may be classified as:
Binary arithmetic operators.
Unary arithmetic operators.
Binary arithmetic operators.
Operator
Operation
+
Addition
Subtraction
*
Multiplication
/
Division
%
Modulo
Unary arithmetic operators.
Operator
Operation
+
unary plus
unary minus
++
increment
-decrement
Relational Operators:
Operator
Operation
<
Lesser than
<=
Lesser than or equal to
>
Greater than
>=
Greater than or equal to
==
Equal to
!=
Not equal to
Relational operators are used to compare two quantities containing relational operator is called a
relational expression.
The value of a relational expression is one (true) or zero (false).
e.g.,
2>4 is false
4<5 is true
The relational expression is of the form:

Ae1 relational operator ae2


Where are1 and ae2 are arithmetic expressions. The arithmetic expressions will be evaluated
first and then the results are compared. The arithmetic operators have a higher priority over
relational operators.
Logical Operators:
Operator
Meaning
&&
Logical AND
||
Logical OR
!
Logical NOT
e.g.,
(a<b)&&(x==y)
(x!=y)||(y<z)
A logical expression also yields a value of one or zero.
Assignment Operators:
An assignment statement is of the form:
Variable=expression;
= is called the assignment operator. The expression will be evaluated and the value assigned to
the variable.
Shorthand assignment operators:
V op = expression;
Where v is a variable, op is a binary arithmetic operator.
e.g.,
a+=5;
The above example is the short form of the statement expression a=a+5;
Bitwise Operators:
C supports a set of bitwise operators for manipulation of data at bit level. Bitwise operators can
be used only for integer type.
Operator
Meaning
&
bitwise AND
|
bitwise OR
^
bitwise exclusive OR
<<
shift left
>>
shift right
Conditional Operators:
A ternary operator pair ?: is available in C. Using this the conditional expression may be
constructed as follows.
exp1?exp2:exp3;
Exp1, exp2 and exp3 are expressions.
Exp1 is evaluated first; if it is true then exp2 will be evaluated and becomes the value of the
expression. If it is false, exp3 is evaluated and its value becomes the value of the expression.
e.g.,
a=5; b=8;
x=(a>b)?a:b;
Other operators:
Operator
Meaning
()
Function
[]
Array

.
->
*
&

Structure member
Pointer to structure member
Pointer variable (indirection operator)
To get the address of the data item stored
in the memory.
To allot memory for the variable.
Comma operator.

Sizeof
,
Initialisation:
Assigning a value to a variable for the first time in a program is known as initialisation. The
value used for the assignment is known as initializer.
e.g.,
int a=5,b=a+5;
int c=a*b;
Escape Sequences:
Escape sequence is a character representation that may appear in a character constant or in a
string constant. The character set does not contain the control characters such as backspace,
tab, enter, etc., to represent such characters, escape sequences are used.
Escape Sequence
Character
\a
bell (alert)
\b
backspace
\f
form feed
\n
new line
\t
horizontal tab
\v
vertical tab
\
double quote
\?
Question mark
\0
null character
\r
carriage return
Comments:
A program comment is written to explain briefly about what a program does. The improve the
readability of a program comments may appear anywhere in a program. /* comments */
Statement Termination (Delimiter):
C is a free format language. Single statement and multiple statements can be on a single line or
they may spread over several lines. Each statement must be terminated by a semicolon.
e.g.,
int a=5,b=35;
x=a+b;
Structure of a C Program:
A C program will have the following structure:
Documentation
File Inclusions
Constant definitions
External Variables (Global) declarations
Function Protypes
main( )
{

Local variable declarations;


Program statements;
}
user-defined functions.
Type Conversion:
When an operator has operands of different data types, expression is said to be in mixed mode.
C supports mixed mode operations in arithmetic expressions. There are two types of
conversions.
Automatic (Implicit) Type conversion
Forcible (Explicit) conversion
The rules for governing automatic type conversion:
If an expression involves two data items of different types, then lower type will be
converted to higher type. The results of the expression will be in the higher type
mode.
The value of the expression on the right hand side of an assignment statement will
be converted into the type of variable on left hand side.
Under some circumstances the automatic type conversion may not be feasible
then we will switch over to forcible conversion. Where one of the data item is
forcibly converted to the required type and then, automatic type conversion will
take over.
When an expression evaluated with help of forcible conversion then the variable
at left hand side of the assignment statement is expected to be forcible converted
type, to get the exact result.
Hierarchy of data types:
high

Long double
Double
Float
Unsigned int
Long int
Int
Short int
Char

low
Input / Output Facilites:
Programming languages are provided with certain facilities for I/O operations and most of them
have inherent I/O facilities for data transfer. But C does not have I/O facility. Input/Output are
carried out by functions, which are part of C library functions. Standard I/O library functions are
available in a filename stdio.h (standard input output header file). The following line must be
included in all programs as follows:
# include <stdio.h>
Character oriented I/O functions:
These functions are used to read or write one character at a time. Getchar( ) and putchar( ) falls
under this category.
getchar( )
The function getchar( ) is used to read a single character from the keyboard.
The format is as follows:
5

variable=getchar( );
putchar( )
The function putchar( ) writes its arguments, which is a character on the screen.
The format is
putchar(arg);
e.g.,
int c;
c=getchar( ); /*entered character is assigned to c */
putchar( c ); /*the character entered is displayed*/
The gets and puts functions:
The gets function is used to enter a string into the computer from a standard input device. The
puts function is used to transfer a function from a computer to any standard output device. Each
function accepts a single argument. The argument must be a single data item that represents a
string; the string may include a blank space.
e.g.,
#include<stdio.h>
main( )
{
char name[25];
gets(name);
puts(name);
}
Formatted I/O functions:
The data can be entered into the computer from a standard input device by means the C library
function scanf. This function can be used to enter any combination of numerical values, single
character and strings.
The syntax for scanf statement is as follows:
scanf(control string, arg_1,arg_2,.., arg_n);
The control string specifies the field format in which the data is to be entered, and the arguments
arg_1, arg_2, . Arg_n specify the address of locations where the data is stored. Commas
separate control string and arguments. Field format specifications consisting of the conversion
character % followed by the type specifier. It may contain the field width.
Entering Integer values as input:
The file specifies for reading an integer value is %wd.
The % sign indicates that a conversion specification follows. W is an integer number that
specifies the field width of the number to be read and the d is the type specifier (data type
character) indicating that the number to be read is in integer mode.
Consider the following example:
scanf(%d%d,&a,&b);
Suppose we have the data
50 40
The value 50 is assigned to a and 40 to b.
It is our responsibility that there is a correspondence between the data items listed in the scanf
and the values given in the data line. If they do not correspond with respect to the type of data
and the field size, unpredicted errors may occur.

Entering real numbers as input:


For reading float values (real), the specifier %f must be used. The values may be given in the
decimal form or in the exponential form.
e.g.,
scanf(%f%f%f,,&a,&b,&c);
suppose we have the data
324.32
2.434 76
The assignment will be 324.32 to a
2.434 to b
76.0 to c
Input of character strings:
A single character can be read from the terminal using the getchar. The same can be achieved
using the scanf function.
For this the specifier is %c.
A scanf function can accept strings contain more than one character. For the specifier is %s
Consider the statement:
scanf(%s,name);
Suppose the data typed is
COMPUTEC
The assignment will be as desired for the same statement, suppose the data typed is
COMPUTEC ASSOCIATES
The assignment will be COMPUTEC.
The specification %s terminates reading as soon as blank space is encountered.
Reading mixed mode data types:
The advantage of using scanf is, a single scanf statement may be used to input a line containing
more than one type of data. We must ensure that the input data items match the control
specifications in order and type.
Control Structures:
A C program is normally executed sequentially in the order in which they appear. This is
enough when there is no option or repetitions of certain calculations are required. In practices,
there are a number of situations where we may have to change the order of execution of
statements based on certain conditions, or repeat a group of statements depending on some
conditions. This involves some kind of decision-making and accordingly transfer of control may
be necessary for the execution of the statements in a program.
C supports a number of decision-making capabilities or control structures which are used for
branching and looping.

Unconditional Branching statement:


A goto statement is meant for unconditional branching. The goto requires a label in order to
identify the place where the control is to be transferred. A label is any valid identifier and a
colon must follow it. The label is placed immediately before the statement where the control is
to be transferred. A goto statement is of the form:
--goto label;
------label:
statement:
---The label can be placed anywhere in the program. During the execution of the program when the
statement
goto label;
Is encountered, control will be transferred to the statement following the label, so the goto
statement is also called as jumping statement.
e.g.,
main( )
{
float x, y;
repeat:
scanf(%f, &x);
y = x * x;
printf(%f\t%f,x,y);
goto repeat;
}
The above given example is of the type backward jumping and the process is repeated
indefinitely.
Conditional Branching Statements:
The IF statement:
The if statement is of the form:
if (condition)
{
statement block
}
statement-1;
--The statement block may be a single statement or a group of statements. If the condition is true,
the statement block will be executed and then control will be transferred to statement-1. When
the condition is false, the statement block will be skipped and the execution will be transferred to
statement-1. The following flowchart will illustrate this

The IFELSE statement


The general form is
if (logical expression)
{
statement block-1
}
else
{
statement block-2
}
statement 3;
--If the logical expression takes the value true statement block-1 will be executed and control will
be transferred to statement-3. If the logical expression is false, then statement block-2 will be
executed and control will be transferred to statement-3. This is illustrated in the following
flowchart.

Nested IF Statement:
When more than one decision is needed, if statements may be nested as follows:
if (logical expression-1)
{
if (logical expression-2)
{
statement block-1;
}
else
{
statement block-2;
}
}
else
{
statement block-3;
}
statement-4;
The interpretation of the above nested structure is as follows:
If logical expression-1 is false, statement block-3 will be executed and control will be transferred
to statement-4.
If logical expression is true, it continues to evaluate logical expression-2.
If logical expression-1 is true, statement block-1 will be executed and control will be transferred
to statement-4.
If logical expression-2 is false, statement block-2 will be executed and control will be transferred
to statement-4.
The ELSE-IF ladder:

The SWITCH statement:


This statement is useful when one of several alternatives required. Hence, it may be considered
as a multiple branching statement.
It is of the form:
switch (expression)
{
case value-1:
Statement-1;
break;
case value-2:
Statement-2;
break;
case value-3:
Statement-3;
break;

10

----case value-k:
statement-k;
break;
default:
statement-L;
break;
}
statement m;
--There are four keywords switch, case, break and default. The structure begins with the keyword
switch. The expression is an integer or character expression. Value-1, value-2 . Are
constants or expressions, but on evaluations they must give integer constants. They are known as
case labels, a colon follows each case label. The constants in the case label need not be
consecutive.
The statements works as follows:
The expression following switch is evaluated, execution control will be transferred to the
statement immediately following the case label when value is equal to the value of the switch
expression. This statement is executed and also the succeeding statements, if any. When the
break statement is encountered, the switch statement is terminated immediately and any
remaining statements in the body are ignored. If the switch is nested in another structure (a loop
or another switch), the outer structure is not altered; only the one immediately containing the
break is terminated.
Default is a special label and the inclusion of this portion is optional. It is a label, which allows
for the possibility that the value of the switch expression does not match any of the case labels.
If none of the case labels match, control will be transferred to the default label and the statement
followed by default will be executed. If the default label is not present and if there is no match
of the case labels, the entire switch statement will be skipped. The default can be placed any
where within the body of the switch statement; it need not be the last label.
For any given label, any number of statements may be included. If more than one statement
follows a label, it is not necessary to group them together within braces.
The action of a switch statement can be explained by the following flowchart:

The WHILE statement:


The while statement is of the form:
11

while (logical expression)


{
statement;
}
statement-1;
The logical expression will be evaluated. If it is true, the statement is executed, control will be
transferred to while and the logical expression is evaluated. If it is true, the statement is executed
and control will be transferred to while and so on. Thus, as long as the logical expression is true,
the statement is executed. When the logical expression is false, the statement will not be
executed and the control will be transferred to the next statement, i.e,. statement-1. This may be
explained by the following flowchart.

/* A program to calculate the sum of the first n natural numbers, using while statement */
#include<stdio.h>
#include<conio.h>
void main( )
{
int i,n;
long sum=0;
clrscr();
printf(\nEnter the value of n : );
scanf(%d,&n);
i = 1;
While (i<=n)
{
sum+=i;
i++;
}
printf(\nThe sum is %ld,sum);
getch( );

12

}
The DO.. WHILE statement:
The do .. while statement is of the form:
do
{
statement;
}
while (logical expression);
The working of a do .. while structure is shown in the following flowchart.

The do while statement is some what similar to while statement, the only difference is that the
logical expression is at the bottom of the loop. Hence, the statements in a do .. while structure
will be executed at least once. The statements will be repeated as long as the logical expression
is false, control will be transferred to the statements following the do .. while.
/* Program to calculate the value of 22 + 42 + 62 + using do while statement */
#include<stdio.h>
#include<conio.h>
void main( )
{
int i =2;
long sum = 0;
do
{
sum+=i * i; i +=2;
}
while (i<=30);
printf(\nThe sum is %ld,sum);
}
Using while and do .. while structures, it is possible to execute a sequence of statement
repeatedly. Hence they are called looping structures. This repetition is conditional because
execution is repeated only when some condition is satisfied. In the while structure, the condition
is tested in the beginning, where as in the do .. while, the condition is tested towards the end. On
entry, if the condition is not satisfied, the statement in the while structure will not be executed at

13

all. In the do while, the statement will be executed at least once because after executing it, the
condition is tested.
In both the structures, there must be some provision in the body of the loop, which will cause the
logical expression to be false after some repetition of the loop, otherwise it will be an indefinite
loop.
The FOR loop:
The general form of the for loop is:
For (expression-1; expression-2; expression-3)
Statement-1
Expression-1 is called an initialization expression. It will be an assignment statement to
initialize the index of the loop. Expression-2 will be a logical expression, which must be
satisfied in order to continue execution of the loop. Only if it is true, the loop will be executed.
If it is false, the execution of the loop will be terminated and Program execution will continue
from the statement following the FOR structure. Expression-3 is called a modifier statement,
which will change the value of the index so that expression-2 will become false after some
iteration. Expression-3 will be executed at the end of each iteration, after the body of the loop is
executed. The statement may be simple or compound. It is the body of the loop, which is
repeatedly executed as long as expression-2 is true.
The action of the for structure is shown in the following flowchart.

/* Program to generate a series using for loop */


#include<stdio.h>
#include<conio.h>
void main( )
{

14

int i;
clrscr ( );
for (i=1;i<=10;i++)
printf (%d\n,i);
getch ( );
}
Nested Loops:
Whenever a loop construct appears within another loop construct we say that it is a nested loop
structure. The loops should not overlap with each other. The variable names used in one loop
construct must be different from another construct. The syntax is:
for (expression-1; expression-2; expression-3)
{
statement-1;
for (expression-4; expression-5; expression-6)
{
statement-2;
}
}
Note: More than two constructs may be nested in the same way. A while loop and a do loop
may also be nested. A for loop may be nested in a while loop or a while loop may be nested in a
for loop and so on.
e.g.,
/* Program to print the number 1 one time, the number 2 two times and so on */
#include<stdio.h>
#include<conio.h>
void main ( )
{
int I,j;
for (I=1; I<=10; I++)
{
for (j=1; j<=I; j++)
{
printf (%d\t,I);
}
printf(\n);
}
getch( );
}
The COMMA Operator:
This is one of special features of C. Using this operator in the for loop, it is possible to have
more than one index in the for loop.
e.g.,
for (I=0, j=n; I<=k; I++, j+=2)
{
-----

15

----}
Hence the initialization expression consists of two variables I and j and they are given the initial
values as I = 0 and j = n. To indicate this, a comma is placed. Up to the first semicolon,
initialization is assumed. Similarly, whatever is written after the test condition, they will be
taken as modifiers. Here there are two modifiers: I++ and j+=2. Note that they are separated by
comma.
/* Program to illustrate Comma operator */
/* Sum of odd numbers */
#include<stdio.h>
#include<conio.h>
void main( )
{
int I, j, n, sum=0; clrscr ( );
printf(Enter the number of odd numbers to added \n);
scanf (%d, &n);
for (I=1, j=1; j<=n; I+=2, I++)
sum+=I;
printf(\ Required sum = %d, sum);
getch ( );
}
Jumps in Loop:
Loops perform a set of operations until a condition is satisfied. While executing a loop,
sometimes it may be necessary to stop a part of the loop or to leave the loop as soon as certain
condition occurs. C permits a jump from one statement to another within a loop as well as jump
out of a loop.
The Break Statement:
The break statement is a jump statement and it can be used inside any of the following
constructs.
Switch statement
For loop
While loop
Do..while loop.
We have already seen that execution of a break statement from within a switch block causes
immediate exit from the switch block and program control is transferred to the statement
following the switch block. In the loop constructs also, execution of the break statement
terminates the loop and further execution of the program is resumed with statement following the
loop.
/* use of break in a for loop */
#include<stdio.h>
#include<conio.h>
void main ( )
{
int m; float x, sum = 0, average = 0; clrscr ( );
printf (Enter the values one by one \n);
printf(Enter the negative numbers to terminate \n);

16

for (m=1; m<1000; m++)


{
scanf (%f, &x);
if (x<0)
break;
sum+=x;
}
average = sum / float(m-1);
printf (\n Number of values : %d,m-1);
printf (\n Sum : %f, sum);
printf (\n Average : %f, average);
getch( );
}
The Program is for entering some non-negative numbers, calculate the sum and average of the
numbers entered. The input and addition is done in a for loop. To terminate the process a
negative numbers is to be entered. On entering a negative number the break statement causes
exit from the for loop. The average is calculated and the results are printed.
The Continue Statement:
This is also a jump statement. Execution of a continue statement does not cause an exit from the
loop, rather it suspends execution of the remaining statements in the body of the loop for the
particular iteration and the control transferred back to the top of the loop and the next iteration
will continue.
The continue statement can be used only inside the for, while and do..while blocks. It must not
be used in switch statements.
The following program evaluates sqrt(n), given the value of n repeatedly. To terminate an input
zero is given. If a negative number is entered, the evaluation is skipped. The program uses
break as well as continue statements.
/* use of break and continue statement */
#include<stdio.h>
#include<conio.h>
#include<math.h>
void main ( )
{
int count = 0, I; double no, rootno; clrscr( );
printf (\n Enter the numbers one by one \n);
printf (\n Enter zero to terminate \n);
for (I=1; I<=1000; I++)
{
scanf (%lf, &no);
if (no==0)
break;
if (n<0)
{
printf (\n The number is negative );
continue;
}

17

rootno =sqrt (no);


printf(\n Number = %f\n square root = %f, no, rootno);
coutnt++;
}
getch ( );
}
Arrays
We know that all variables in a C program must be declared in advance. In some applications,
the number of variables needed in a program may not be fixed and that it may not be known in
advance. It may be a tedious process to get names of several variables, their declarations and
manipulations. This situation is handled by using subscripted variables.
Definition: Array is a mode of amalgamation of homogenous collection of data in conjunctional
locations so as to share a common entry code (name) identifiable by their subscripts.
The declaration is of the form: (linear array)
Type array-name[array-size];
Type refers to the data type of the elements contained in the array. It may be int, float, char
size represents the maximum number of elements to be stored in the array.
e.g.,
int mark[50];
The declaration is for an array, its members are of type int and that it has a maximum of fifty
elements. Mark is the name of the array.
The members are referred to as mark [0], mark [1], . Mark [49]. Note that the subscripts are
enclosed in square brackets and that the subscript starts with zero. The subscript must be a nonnegative integer. The subscript gives the relative position of the item in the array. The subscript
may be a constant, variable or expression.
Reading, writing or manipulating an array must be done element wise. Whole vector (array)
operations are not permissible, except for some special cases. For instance, to assign values for
the elements, we may use a looping structure and supply the values one-by-one succession. A
similar process is required for printing or manipulating.
Suppose a, b, c are three arrays of the same type and of the same size. The statements
a=b;
b=a+c;
Are not valid.
/* A sample for array */
#include<stdio.h>
#include<conio.h>
void main( )
{
int a[100], I,n; clrscr ( );
printf (\n Enter the size of array : );
scanf (%d,&n);
printf (\n Enter %d elements to store in the array : \n,n);
for (I=0; I<n; I++)
scanf (%d, &a[I]);
printf (\nThe entered array elements : \n);

18

for (I=0; I<n; I++)


printf (%d\t, a[I]);
getch ( );
}
Initializing Arrays
It is possible to give initial values to the elements of an array when it is declared. The format is
Static type name [size] = {list of values}
e.g.,
static float a [4] = {3.2, 5.8, 9.1, 13.4};
The statement above is a declaration of an array a of type float and the initial values are
A[0]=3.2, a[1]=5.8, a[2]=9.1, a[3]=13.4
If the initial values are given, the size of the array may be omitted in the declaration. The above
declaration may also be given as
Static float a[] = {3.2, 5.8, 9.1, 13.4}
The compiler understands that the size is 4 and with initial values
A[0]=3.2, a[3]=3.4
e.g., Consider the declaration
static char institute [] = {C, A};
The compiler understands that institute is an array of type char with size 2 and that
Institute [0] = C
Institute [1] = A
If any array is to be initialized, all elements of the array must be given initial values. It is not
permitted to give initial values only to some of the elements. Hence the declaration,
Static int x [5] = {4,3};
Is invalid, because the size is declared as 5 and the initial values are given only for 2 elements.
Multidimensional Arrays:
What we have discussed so far, is concerned with a one-dimensional (linear) array. The
dimension of an array is equal to the number of subscripts present.
A two dimensional array is declared as follows:
Type name [row-size][column-size];
A two-dimensional array requires two subscripts to identify a member and we call them the row
number and column number. In the declaration, maximum number of rows and maximum
number of columns contained in the array must be specified. The two subscripts must be
enclosed in separate square brackets. The concept can be extended to higher dimensional arrays.
Consider the declaration
int mat [3][4];
It means mat is a two dimensional array of type int, with a maximum of three rows and
maximum of four columns. Each dimension is indexed from zero. Hence the members of array:
mat [0][0],
mat [0][1],
mat [0][2], mat [0][3]
mat [1][0],
mat [1][1],
mat [1][2], mat [1][3]
mat [2][0],
mat [2][1],
mat [2][2], mat [2][3]
A two-dimensional array can be initialized as it is done for a one-dimensional array. The values
are given row-wise.
e.g., the declaration
static int a [3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
will remain that the two-dimensional array a is given as

19

1
2
3
4
5
6
7
8
9
10
11
12
Here is a variation of two-dimensional array definition presented in the last example.
int a [3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
/* A sample program for 2-d array */
#include<stdio.h>
#include<conio.h>
void main( )
{
int a [3][3], I, j;
clrscr ( );
printf (\n Enter the elements of matrix of order 3X3 \n);
for (I=0; I<3; I++)
for (j=0; j<3; j++)
scanf (%d, &a [I][j]);
printf (\n The entered elements of a matrix \n);
for (I=0; I<3; I++)
{
for (j=0; j<3; j++)
{
printf (%d\t, a[I][j]);
}
printf (\n;
}
getch ( );
}
String Handling:
A string is an array of characters. It is declared as follows:
char name [size];
The size specifies the number of characters in the string. When the compiler assigns a character
string to a character array, it automatically supplies a null character (\0) at the end of the string.
We must include one extra space in the array to store the null character. Consider the declaration:
char name [20];
Name is declared as a character array that can hold a maximum of twenty characters. But the
last space is always reserved for the null character. Hence the string may contain a maximum of
19 characters. The length of the string is the number of non-null characters in the string. It is
one less than the size specified in the declaration. The allocation will be as follows:
a

Input / Output of Strings:

20

For reading a string of characters, the scanf function may be used with %s format specification.
E.g.,
char city [25];
scanf (%s, city);
Note that in the scanf function, the ampersand (&) is not required before the variable name. And
also previously, it was mentioned that input /output on arrays as a whole is not permitted, but a
character array is an exception to this. In the example considered, city was declared as an array
of characters and
scanf (%s, city);
Will read the array as if it is an ordinary variable.
For printing a string the printf function may be used with the format specification %s.
The statement
printf (%s, city);
However, it is not permissible to have operators directly on strings. E.g., the statement
city = BANGALORE;
Is not valid.
Similarly, if string1 and string2 are declared as character arrays, the assignment
string1 = string2;
Is not valid.
The scanf function has a problem with strings. The input will be terminated by a blank space (or
tab, carriage return, form feed, new line). Hence it is suitable only if the string has only one
world.
Consider the statement
scanf (%s, city);
Suppose we type
CYBER CITY
Then, only the string CYBER will be read into the array city because the blank space following
CYBER will terminate the string. There are two alternatives for this problem. Using the getchar
( ) function, input may be given character by character.
Consider the example:
char institute [30];
Int I;
In order to supply input to the string name (i.e., for the character array) we may write
For (I=0; I<30; I++)
Institute [I] = getchar ( );
When the data is typed, successive characters including blank spaces will be read into the
elements of the array. The reading terminates when I = 30. Thus, the assignment is for the
subscripts 0 to 28 (only 29 characters) and the last character is the null character.
Alternative, we may write
for (I=0; I<30; I++)
scanf (%c, &institute [I]);
Printing of strings will be possible in the same way. The other library functions available for
reading a string and displaying a string are gets and puts.
Functions for Handling Strings:
A number of functions are available in the C library for handling strings. Here we consider some
of them.

21

strcpy ( ):
The strcpy function works like an assignment statement. It is of the form:
strcpy (string1, string2);
It will assign the contents of string2 to string1.
Suppose we have string2 as COMPUTEC. The above statement will cause the assignment of
COMPUTEC to string1.
strlen ( ):
This function is used to find the number of characters in a string. It is of the form: strlen (str);
Where str refers to the string.
Consider the statement:
n = strlen (city);
Where city is the name of a string. Then, the number of characters in the city is assigned to n,
where n is the integer variable.
strcat ( ):
This function is used to join two strings together nothing but concatenating the strings. It is of
the form:
strcat (string1, string2);
On encountering the above statement string2 will be appended to string1. String2 will remain
the same.
Suppose str1 and str2 are two strings and st1 = COMPUTEC and st2 = ASSOCIATES.
Execution of the statement
strcat (str1, str2);
Will result in
str1 = COMPUTEC ASSOCIATES
str2 = ASSOCIATES
When we use strcat function, we must make sure that string1 is large enough to hold both the
strings.
strcmp ( ):
Two strings cannot be compared directly. Suppose name1 and name2 are the names of the two
strings, then the statement
if (name1==name2)
Is not valid. In order to compare two strings, they will be tested character by character. The
library function strcmp ( ) is used to compare two strings. It is of the form:
strcmp (string1, string2);
Where string1 and string2 are the names of the strings.
This function will return the value zero if both the strings are equal; otherwise, it will return an
integer, which is the difference between the ASCII equivalents of the first mismatch between the
characters of string1 and string2.
For instance, if we write
strcmp (RAJA, RANI);
The function will return the value, which is the ASCII value of J minus ASCII value of N, since J
and N are the first mismatching characters.
strrev ( ):
This function is used to reverse a string. It is of the form:
strrev (string1);
Where string1 is the name of the string.

22

e.g.,
strcpy (string2, strrev (string1));
suppose if string1 = COMPUTEC.
Then string2 = CETUPMOC.
toupper ( ) and tolower ( ) functions:
These two functions operate on a single character. The function toupper ( ) checks the character
given as its arguments and if it is in lower case, converts it into upper case.
In a similar manner, the function tolower ( ) checks the character given as its arguments and if it
is in uppercase, converts it into lowercase. The syntax is:
toupper ( c );
tolower ( c );
Where c is the character to be converted.
sscanf and sprintf functions:
These two library functions are derived from printf and scanf. They do not perform input or
output.
The function sprintf copies information into a string.
The syntax of sprintf is:
sprintf (s, formatstring, arguments);
Here s is the buffer, i.e., an array of characters. Format string and argument list are similar to
those used with printf. The difference is that the output is given to the string instead of to the
monitor. This function also appends a NULL character at the end of the string.
e.g.,
int x = 25;
char string [10];
sprintf (string, %d, x);
The function will write the two digits 2 and 5 followed by a NULL character in the array string.
The effect is
strcpy(string,25);
The function sscanf performs opposite conversion. It gets information from the string in the
same way scanf( ) gets information from the keyboard. The syntax is:
sscanf (s, format string, list of addresses of variables);
Here s is the string to be disassembled into data items and the data assigned to variables
according to the format specified in the format string.
e.g.,
int x; char ch; float f;
char string[20] = 6t3.24;
sscanf(string, %d%c%f, &x, &ch, &f);
The assignment will be 6 to x, the character t to ch and 3.24 to f.
Functions
Built-in functions are pre-defined and supplied along with the compiler and may be used in any
C program. They are also known as library functions. Already we are using some of I/O
functions getchar ( ), putchar ( ), scanf ( ), printf ( ), gets ( ), puts ( ), clrscr ( ) . And the
mathematical functions sqrt( ), sin ( ), cos ( )
Functions defined by the programmers (users) are called as user-defined functions.

23

A function is a self-contained program segment that carries out some specific, well-defined task.
Every C program consists of one or more functions. One of these functions must be called main.
Execution of the program will always begin by carrying out the instructions in main ( ).
Additional functions will be subordinate to main, and perhaps to one another. If a program
contains multiple functions, their definitions may appear in any order, though they must be
independent of one another. That is, one function definition cannot be embedded within another.
A function will carry out its intended action whenever it is accessed (i.e., whenever the function
is called) from some other portion of the program. The same function can be accessed from
several different places within a program. Once the function has carried out its intended action,
control will be returned to the point from which the function was accessed.
Generally, a function will process information that is passed to it from the calling portion of the
program and return function via special identifiers called argument (also called parameters) and
returned via the return statement. Some functions however, accept information but do not return
anything where as some functions may return multiple values.
Advantages of functions:
Many program require that a particular group of instructions be accessed repeatedly from several
different places within the program. The repeated instructions can be placed within a single
function, which can then be accessed whenever it is needed. Moreover, a different set of data
can be transferred to the function each time it is accessed. Thus, the use of function avoids the
need for redundant (repeated) programming of the same instructions.
A complete program can be broken up into a number of smaller sub programs.
A program written as a sequence of functions with each function carrying out a specified task, it
is easy to understand. Such a program is also easy to modify.
Commonly used functions may be generalized, tested thoroughly and kept in a library for future
use.
Functions develop by others may be used.
To make use of the user-defined functions, the programmer must
Define a function
Declare the prototype of a function
Invoke the function.
Function definition:
A function definition describes what a function does, how its actions are achieved and how it is
used. It consists of a function header and a function body. The format for defining a function is:
Return-type function-name (parameters) /*function header */
{
declarations;
statements;
function body
return(expressions);
}
The first line is known as the function header. The function header is not terminated by a semicolon. The function body follows the function header and is always enclosed in braces. The
body of the function is composed of declarations and statements. The statements describe the
actions to be performed by the function.
Return-type: Specifies the data-type of the value returned by the functions. If the return-type is
omitted, the value return is assumed to be an int type by default Void is specified in place of
return type if the function returns no value.

24

Function name: Function name is an identifier. It cannot begin with underscore because such
names are reserved for the use of C-library.
Parameters: Arguments are known as formal arguments or formal parameters. Zero or more
parameters may be used. Each parameter must be preceded by its data-type. Commas must
separate parameters. Parameters are used to pass the value into the function. For functions without
parameter, the keyword void is placed within the parenthesis following the function-name.

Return statement: It consists of the keyword return followed by an expression within


parentheses and it returns a single value to the calling function. If there is no expression, it
means the function is not returning any value. A function may contain more than one return
statement.
The expression may be a constant, a variable or an arithmetic expression that yields a value. The
value is converted to the return-type of the function before being returned. The function
terminates after executing the return statement. A function returns to the calling function after
reaching return statement.
Function declaration:
Whenever a function is invoked in another function, it must be declared before use. Such a
declaration is known as function declaration or function prototype. Function declaration ends
with a semicolon. The general format of function declaration is:
Return-type function-name (parameter-list);
In a function declaration, parameter names in the parameter-list are optional. It is permissible to
have the data type of each parameter without mentioning the parameter name. The following
declaration is valid.
Return-type function-name (data-type, data-type);
The return-type is void when a function returns no value. A parameter less function is declared
by writing void inside the parentheses.
e.g.,
void function-name (void);
void function-name (int, int);
float function-name (void);
Function call
A function is invoked in order to make use of it. The general format of a function call is
Function-name (e1, e2, . En);
Where e1, e2, . En are argument expressions. For a parameterless function, there is no
argument in the function call also. The arguments e1, e2, en in a function call are called
actual parameters.
If a function returns a value, the function call may appear in any C expression and the value
returned is used as an operand in the expression. If a function returns no value, it is a statement
and is of the form:
Function-name (e1, e2, . En);
The formal and actual arguments must agree in order and data-type.
When a function is invoked, program execution is transferred to the first statement in the called
function. When the called function terminates, it returns to the calling function and the execution
continues from the subsequent statement after the function call.
/* program to check whether a given integer is palindrome or not using functions */
#include<stdio.h>
#include<conio.h>
int reverse (int num);

25

void printpalin (int a);


void printnotpalin (int a);
void main ( )
{
int x; clrscr ( );
printf (\n Enter an integer : );
scanf (%d, &x);
if (x == reverse (x))
printpalin (x);
else
printnotpalin (x);
getch ( );
}
int reverse (int n)
{
int digit, rev=0;
while (n!=0)
{
digit = n%10;
rev = rev * 10 + digit;
n/=10;
}
return (rev);
}
void printpalin (int k)
{ printf (\n The entered number %d is a palindrome \n, k); }
void printnotpalin (int k)
{ printf (\n The entered number %d is not palindrome \n, k); }
Recursion:
Recursion is a process by which a function calls itself repeatedly until some specified condition
has been satisfied. The process is used for repetitive computations in which each action in terms
of a previous result. Many iterative (i.e., repetitive) problems can be written in this form.
In order to solve a problem recursively two conditions must be satisfied. First the problem must
be written in a recursive form and second the problem statement must include a stopping
condition.
/*Program to calculate the factorial of an integer quantity using recursion*/
#include<stdio.h>
#include<conio.h>
long int factorial (int n);
void main ( )
{
int n, fact;
clrscr ( );
printf (\nEnter the value for n : );
scanf (%d, &n);

26

fact = factorial (n);


printf (\n Factorial of %d is %d, n, fact);
getch ( );
}
long int factorial (int k)
{
int result;
if (k == 1)
result = 1;
else
result = k*factorial (k-1);
return (return);
}
The main function reads the integer n and then calls the recursive function factorial. The
function factorial calls itself recursively with an actual argument (k-1) that decreases in
magnitude for each successive call. The recursive calls terminate when the value of the actual
argument becomes 1. Finally the factorial value is returned to the main function where it is
printed.
Call by value:
A function definition contains an argument list. Items in the list are known as formal arguments
or formal parameters. The list may be empty or may contain a number of arguments. The
calling routine specifies an argument list to be passed to the function. The arguments in the
calling routine are called as actual arguments. The number of actual arguments and the number
of formal arguments must agree in the number, type and order.
Call by reference:
A function may alter the value of the variable passed to it. This method is called call by
reference. For this purpose, the variable must be a global one, which can be accessed by all
functions in the program, or the value of the address of the variable must be passed as arguments
and the formal parameters must be pointers.
Local and Global Variables:
Variables declared within the functions are called local variables. A variable declared inside a
function is said to be local to the function in which it is declared. The names of local variables
have meaning only within the function in which they are declared. Consider the following
program:
/* Area of square */
#include<stdio.h>
#include<conio.h>
int square (int); /*function prototype */
void main ( )
{
int side, area;
printf (\n Enter the side of a square : );
scanf(%d, &side);
area = square (side);
printf (\n The area of the square : %d, area);
getch ( );

27

}
int square (a) /* function definition */
int a;
{
int s;
s = a*a;
return (s);
} /*end of function square */
Statements within the square function can refer to the variable s, but statements in main cannot
refer. If a reference to s is made in main function, an error will be reported. Similarly, the
function square cannot directly refer to the variables side and area. These variables can be
referred to only within the main function in which they have been declared. This phenomenon is
referred to as scope. The scope of a variable refers to the range within a program over which that
variable has meaning.
A variable exists only when the function that contains the variable is in execution. Thus the
variable s in the example will not exist until the function square is called. When execution of the
function is complete, the variable also disappears.
Declaring a variable with the same name in two functions will not make it possible to use that
variable to communicate between functions. This can be seen from the following example.
#include<stdio.h>
#include<conio.h>
int modify ( ); /*function prototype*/
void main ( )
{
int a=5; clrscr ( );
printf (\n The value of a is %d, a);
modify ( );
printf (\n The value of a after the function call is %d, a);
getch ( );
}
int modify (void) /*function definition*/
{
int a;
a = 25;
return (a);
}
The variable a is declared in 2 functions main ( ) and modify ( ). In the main function, the
value of a is 5. In function modify ( ) the value of a is 25. When the program is executed, the
output will be
The value of a is 5
The value of a after the function call is 5.
The main function declares a and assigns the value 5. This value is printed, then the function
modify ( ) is called. The function creates its own local variable a and assigns the value 25 to it.
This assignment will have no effect on the variable name a that was created by the main
function. When control returns to the main function, the variable a local to main still contains
the value 5 and that is printed.

28

A function does not terminate its execution when calling another function; it only suspends
execution. Hence, the variable a local to main remains while the function modify is in execution.
The variable a is main will disappear only when main finishes execution, which is the
execution of the entire program.
Two-way communication between functions can be made through the use of global variables.
These variables are not declared within a specified function and hence are accessible to all
functions in the program. Consider the following:
/* program to illustrate global variables*/
#include<stdio.h>
#include<conioh>
int getside ( );
int calculate ( );
int side, area;
void main ( )
{
printf (Enter the side of the square : );
side = getside ( );
calculate ( );
printf (\nThe area of the square is %d, area);
getch ( );
}
int getside ( )
{
int a;
scanf (%d, &a);
return (a);
}
int calculate ( )
{
area = side*side;
}
The function main and calculate use the global variables side and area. The function getside uses
a local variable a.
The variables side and area are global because they are not declared within the body of any
function. Usually, global variables are declared in the beginning of a program, before the main
function.
Note:
The main function has no declaration for the variables side and area. If it has, they will be
considered local to main. According to scope rules in C. If a local variable is given the same
name as a global variable, the function declaring the local variable can refer only to the local
variable and not to the global variable of the same name.
Storage Classes
A variable in C is in one of the four storage classes.
Automatic Variables
External Variables
Static Variables

29

Register Variables
We consider the scope and lifetime of each of the classes. The scope of a variable determines
over what part of the program a variable is available for use. Lifetime refers to the period during
which a variable retains a given value during execution of a program.
Automatic Variables:
Automatic variables are declared inside a function in which they are to the utilized. They are
created when the function is called and destroyed automatically when the function is exited.
They are local or private to the function in which they are declared because of this property they
are also called local or internal variables. A variable declared inside a function without storage
class specification is by default an automatic variable.
e.g., the following two declarations are the same.
main ( )
{
int I;
------}
main ( )
{
auto int I;
------}
A variable local to the main function will be normally alive throughout the program, although it
is active only in main.
External variables:
Variables, which are both active and alive throughout the program, are known as external
variables. They are also known as global variables. Global variables are accessed by any
function in the program.
e.g.,
int I; float a;
main ( )
{
------}
function1 ( )
{
------}
function2 ( )
{
------}

30

The variable I and a will be available to all the three functions main, function1 and function2.
In case a local variable and a global variable have the same name, the local variable will have
precedence over the global variable in the function where it is declared.
Consider the example:
Int I;
Main ( )
{
I = 100;
}
function1 ( )
{
int I = 0;
--I = I + 1;
--}
When function1 references i, it will be referencing only the local variable I and not the global
one. Hence, the value of i in the main function will not be affected.
One feature of a global variable is that is it is visible only from the point of declaration to the end
of the program. Consider the example:
main ( )
{
y = 10;
----}
int y;
function1 ( )
{
y = y+1;
--}
In the example above y is referenced in main, but is not defined in it. Hence, an error message
will be displayed. This problem can be solved by declaring the storage class as extern as shown
in the example below.
main ( )
{ be a constant expression. A static variable without an initializer is set to zero. If the value is
changed during the execution, the recent value is retain. When the execution enters the next time
in the same block, the initializer is neglected and recently stored value is retained. Thus, an
internal static variable has persistent storage, block scope and no linkage.
If a static variable is declared before main ( ), i.e., outside all the blocks in a source file, it is
known as an external variable. An external static
extern int y;
---}
function1 ( )

31

{
extern int y;
--}
The variable y has been defined in the main and function1. The declaration y as an external
variable instructs the compiler that y is an integer type and its definition appears somewhere in
the program. Inside the functions main and function1, a reference to y is permitted. Whenever
an external variable is modified in a block, the effect is propagated to all places it is used because
of its global scope. The latest value is retained.
main ( )
{
extern x; int y =10, z;
z =y/x;
printf (\n x = %d\n y = %d\n z = %d; x, y, z);
}
int x = 5;
Static variables:
Any variable declared with the keyword static is treated as a static variable. A static variable can
be internal static or external static based on the place of its declaration. Both the static variables
are declared using the keyword static. If a static variable is declared inside a block, it is known
as internal static variable. The storage used by an internal static variable in a block is not lost
after the completion of the execution. Even after the termination of the block, the value of the
static variable is available. If the internal variable is initialized inside a block, it is initialized
only once. The initializer must be a constant expression. A static variable without an initializer
is set to zero. If the value is changed during the execution, the recent value is retained. When
the execution enters the next time in the same block, the initializer is neglected and recently
stored value is retained. Thus, an internal static variable has persistent storage, block scope and
no linkage.
If a static variable is declared before main ( ), i.e., outside all the blocks in a source file, it is
known as an external variable. An external static be a constant expression. A static variable
without an initializer is set to zero. If the value is changed during the execution, the recent value
is retained. When the execution enters the next time in the same block, the initializer is
neglected and recently stored value is retained. Thus, an internal static variable has persistent
storage, block scope and no linkage.
If a static variable is declared before main ( ), i.e., outside all the blocks in a source file, it is
known as an external variable. An external static variable has permanent storage, file scope and
internal linkage. Initiasation of an external static variable assigns the initialized value when the
program begins its execution. It is initialized only once. The initialiser must be a constant
expression. The recent value is retained when the execution starts next time.
Some valid declarations
Static int a, b, c=5;
Static float x=2.5,y;
Advantages of the Static Variables:
The scope helps in accessing the variable globally within a file. Change of value in any
place within the file is available in its scope.

32

Previous value is retained even after the completion of the execution of the block, but
before the completion of the execution of the program.
Initialization is done only once and the value is retained.
An internal static variable is a local variable and in external static variable is a global
variable. Based on he requirement, it may be declared accordingly.
Eg..
/*program to illustrate internal static variable*/
#include<stdio.h>
#include<conio.h>
void main( )
{
int i,x=2,y=10;
printf(x=%d\ny=%d\n,x,y);
for(i=1;i<=3;I++)
{
static int z = 100; /*internal static variables*/
printf(\n x = %d\ny=%d\nz=%d, x, y, z);
z=z/x;
y=y+z;
}
}
The output will be
x = 2 y = 10
x = 2 y = 10 z = 100
x = 2 y = 60 z = 50
x = 2 y =85 z = 25
If the storage class static is omitted, it will be treated as an auto storage class by default. In this
case, the output will be:
x = 2 y =10
x = 2 y = 10 z = 100
x = 2 y = 60 z = 100
x = 2 y = 110 z = 100
/*program to illustrate an external static variable */
static float x = 5.00; /*x is a external static variable*/
void main ( )
{
float y = 2.0;
printf (\n x = %f\t y = %f, x, y);
{
float y = 3.14;
x = y * 3;
printf (\n x = %f, y = %f, x, y);
}
printf(\nx = %f, y = %f, x, y );
}

33

The output will be


x = 5.00 y = 2.00
x = 9.42 y = 3.14
x = 9.42 y =2.00
The variable x is declared as an external static variable and initialized as 5.00. In the program,
the outer block contains an auto variable y declared and initialized with the value 2.00. The
inner block has a variable declared as auto with the same name y, with initial value 3.14. The
statement x = y*3 is evaluated as 3.14 * 3 producing the result 9.42. Since x is a external static
variable, its recent value is available throughout the program. Hence the values of x and y in the
outer block are printed as 9.42 and 2.0.
Register Variables:
The register storage class is specified by using the keyword register in the declaration. The
scope, longevity and linkage of the register variables are some as that of the auto variables.
Register variables may be declared in places where auto is allowed. To perform any operation,
the data available in the memory is transferred to the CPU registers. If the date stored in the
register itself, the time for the data transfer from the memory to the register is saved. The access
is faster if the registers are used for storing the data. Heavily used variable may be declared as
register variables to improve the access speed.
The following are some valid declarations:
register int a = 5;
register char ch = a, c = b;
Only few values can be placed in CPU registers. Hence, it is advisable to use limited register
variables.
POINTERS
C provides means to access individual memory locations and to modify their contents. This is
achieved by the use of pointers. In this capability, C is comparable to an assembly language.
Availability of pointers in one of the factors for the versatility of C.
Pointer Variables:
A pointer is a variable that is used to store the address of a memory location. Let I be an integer
variable, if p is another variable used to store the address of the variable I, the p is called a
pointer variable, pointing to the address of the variable.
A pointer variable must be preceded by an asterisk (*), while defining it. The definition of a
pointer variable must also specify the type of data stored in the target variable pointed to by it.
e.g.,
p
i
In the example, the target variable I is holding integer type of data and hence the pointer variable
p must be defined as of type int as follows:
int *p;
The operator & is used in C to denote the address of its operand, which is a variable. Thus &I is
the address of the integer variable i. Since P stores the address of I, we have
p = &i;
The definitions of I and p and their relationship is a follows:
int i;

34

int *p;
p = &i;
Both * and & are unary operators, required only one operand.
The syntax for defining a pointer variable is
Type *variable-name;
Note:
(i)
The variable name must be always preceded by *
(ii)
The type must correspond to the type of data stored in the address i.e., the type of data
stored in the target variable.
Some valid declarations are:
float *a;
char *ch;
double *x;
The pointer variable a points to a memory location containing a float. The pointer variable
ch points to a memory location containing a character. The pointer variable x points to
memory locations containing a double.
Initialization of a pointer variable:
When a pointer variable is defined, a memory location for it is allocated. But the contents of
that location are not known. The location contains some arbitrary data, i.e., garbage. When
the uninitialized pointer variable is used, it may lead to unpredictable results. Hence, a
pointer variable should never be used for data manipulation until it is initialized.
Consider the following definitions of ordinary variables and the corresponding pointer
variables.
int I = 100;
float f = 2.5;
char c =a;
int *pi;
float *pf;
char *pc;
After this definition, for the three pointer variables, memory locations will be allotted, but
they are not yet initialized.
There are two methods to initialize pointer variables. In the first method, the address of
another variable already defined is assigned to the pointer variable.
e.g.,
pi = &i;
pf = &f;
pc = &c;
In the second method, contents of * previously defined variables are assigned as the contents
of the address referred by the pointer variable.
e.g.,
*pi = i;
*pf = f;
*pc = c;;
/* program for defining and initializing pointer variables*/
#include<stdio.h>
#include<conio.h>

35

void main ( )
{
int I, *pi;
float f, *pf;
char c, *pc;
I=100;
f = 2.5;
c = a;
printf(\ni = %d\t f = %f \t c = %c, I, f, c);
printf (\nAddress of I = %d\t f = %d\t c = %d, &I, &f, &c);
printf (\nBefore initialization of pointer variables :\n);
printf (\nAddress of pi = %d\t pf = %d\t pc = %d, &pi, &pf, &pc);
printf (\nValue of pi = %d\t pf = %d\t pc = %d, pi, pf, pc);
pi = &I; pf = &f; pc = &c; /*pointer variables initialized*/
printf (\nAfter initialization of pointer variables: \n);
printf (\nvalue of pi = %d\t pf = %d\t pc = %d, pi, pf, pc);
printf (\n value of *pi = %d\t *pf = %f\t *pc = %c, *pi, *pf, *pc);
getch ( );
}
Pointers as Function Parameters (Call by reference):
While discussing functions we saw that a function was called by passing the values as
arguments to the called function. In other words, only copies of the values are passed on and
the called function cannot alter the original values. This is because the called function has no
access to the variables. Also, a function can return only one value to the called function.
With the use of pointers it is possible:
To provide means of accessing and altering the variables in the called function.
To return more than one value to the called function indirectly.
In this, method, the value of a pointer variable is passed to the called function. Since the
value of the pointer variable is the address of its target variable, the called function can
access that variable using the address and manipulate or alter the value stored. This is known
as passing by reference.
The values of any number of pointer variables can be passed to the called function, which
can manipulate the values stored therein. These modified values become available to the
called function automatically. The calling function also knows their addresses because of
this arrangement; the called function is able to return more than one value to the called
function.
In call by reference the address of the target variable is passed to the called function as actual
parameter. In the called function receiving this address, it should be assigned to a pointer
variable.
Example:
The program passes two parameters viz the addresses of x and y to the function square ( ). In
the function definition the formal parameters are shown as pointer variables.
/*program for call by reference*/
#include<stdio.h>
#include<conio.h>
void square (int *, int *); /*function prototype*/

36

void main ( )
{
int x, y;
x = 10;
square (&x, &y); /*function call with addresses of x and y*/
printf (\n Value of x = %d, x);
printf (\n Value of square of x = %d, y);
}
void square (int a, int b) /*function definition*/
{b = (*a) * (*a); }
The output of the program will be as follows:
Value of x = 10
Value of square of x = 100;
Note that there is no return statement in the function.
Here we consider the called function returning two values to the calling function. The
address of three variables are passed to the called function power ( ). The function evaluates
the square and cube of x and places them in y and z. The variables a, b and c contain the
addresses of x, y, z. The called function will return two values to the called function
indirectly by using the pointer variables.
#include<stdio.h>
#include<conio.h>
void power (int *, int *, int *);
void main ( )
{
int x, y, z; x = 10; clrscr ( );
power (&x, &y, &z);
printf (\n Value of x = %d, x);
printf (\n Value of square of x = %d, y);
printf (\n Value of cube of x = %d, z);
}
void power (int *a, int *b, int *c)
{
*b = (*a) * (*a);
c = (*b) * (*a);
}
Pointer to a pointer:
A pointer contains an address of a variable that variable can also be pointer variable
containing the address of another variable.
If x is an integer variable and P1 a pointer variable containing the address of x, then
P1 = &x;
*p = x;
Let p2 be another variable containing the address of p1.
i.e.,
p2 = &p1;
and
*p2 = p1;

37

Now x can be referenced from p1 as well as p2 as follows:


*p1 = x;
**p2 = x;
In this example, p2 is a pointer to a pointer. Pointer p2 contains the address of p1, which in turn
contains the address of x, the target variable. Providing two indirection operators ** preceding
p2 defines that p2 is a pointer to a pointer. *p2 will get the value of p1 and **p2 will get the
value of x. This concept is called multiple indirections.
/* Program to illustrate the concept of pointer to pointer */
#include<stdio.h>
#include<conio.h>
void main ( )
{
int x, *p1, **p2;
x = 100;
p1 = &x;
p2 = &p1;
printf (\n Address of x = %d, &x);
printf (\n Address of p1 = %d, &p1);
printf (\n Address of p2 = %d, &p2);
printf (\n value of x = %d, x);
printf (\n value of p1 = %d, p1);
printf (\n value of p2 = %d, p2);
printf (\n value of *p1 = %d, *p1);
printf (\n value of *p2 = %d, *p2);
printf (\n value of **p2 = %d, **p2);
getch ( );
}
Structures
Introduction:
In many real-life situations, it is desirable to store data of different types, say strings and integers,
in one data structure. It is not possible however, to use a single C array for this purpose. As we
have seen, elements of an array must be homogenous. This chapter introduces us to a feature of
C, which helps to solve this type of problem.
Definition:
Structure is the mode of amalgamation heterogeneous collection of data in conjunctional
locations so as to share a common entry code identifiable by their members.
The composition of a structure may be defined as:
struct tag
{
type member-1;
type member-2;
type member-3;
----type member-n;
};

38

In this declaration, struct is a required keyword; tag is a name that identifies structures of this
type (i.e., structures having this composition); and member-1, member-2,.. member-n are
individual member declarations (Note: There is no formal distinction between a structure
definition and a structure declaration; the terms are used interchangeably).
The individual members can be ordinary variables, pointers, arrays or other structures. The
member names within a particular structure must be distinct from one another. Though a
member name can be the same as the name of a variable that is defined outside of the structure.
A storage class, however cannot be assigned to an individual member and individual member
cannot be initialized within a structure type declaration.
Once the composition of the structure has been defined individual structure-type variables can be
declared as follows.
Storage-class struct tag variable-1, variable-2, ..variable-n;
Where storage-class is an optional storage class specifier, struct is a required keyword, tag is the
name that appeared in the structure declaration, then variable-1, variable-2, are the structure
variables of type tag. It is possible to combine the declaration of the structure composition with
that of the structure variables as shown below:
storage-class struct tag
{
member-1;
member-2
------member-n;
} variable-1, variable-2, ., variable-n;
the tag is optional in this situation.
Operators used in structures:
Some of the operators exclusively used in structures, they are as follows
. (Dot operator)
= (Assignment operator)
-> (Arrow operator)
The definition of structure variables may be given along with the template:
struct employee
{
char name[25];
int number;
float basicpay;
} emp1, emp2;
Accessing members of a structure:
The dot (.) operator is used to refer to individual members of a structure. With reference to the
example considered, the members may be referenced as follows:
emp1.name
emp2.basicpay
The structure variable name is followed by the dot operator and is followed by the name of the
member. If the member is an array, the individual elements of the array can be referenced with a
subscript.
e.g.,

39

emp1.name[10]
The syntax of referring a structure member is
structvarname.membername
The above reference can be used either to retrieve the data or to modify the value of the member.
Some examples of accessing the members are:
emp1.name=Narayana;
emp2.basicpay = 12000.00;
printf(%f, emp2.basicpay);
Structure Assignment:
When two structure variables, say emp1 and emp2 are defined with the same type of structure,
i.e., with the same tag name such as employee, one variable can be assigned to the other.
e.g.,
emp2 = emp1;
With this assignment, the values of all the members of emp1 will be copied to the corresponding
members of emp2. Note that both the variables should be defined with the same tag name.
Initialization of structure members:
The rules for initialization of members of a structure are similar to those of array initialization.
The members of global or static type of structures variables can be initialized collectively but the
members of local structure variables (i.e., auto type) can be initialized only member by member.
Suppose emp1 is defined as a global of the structure employee, it can be initialized along with its
definition as
struct employee emp1 = { arun, 645, 8000.00};
If emp2 is a local variable, the members are initialized individually as follows:
emp2.name = AJAY
emp2.number = 344
emp2.basicpay = 6500.00
Array of structures:
We can have an array in which each item is a structure. Consider the following example:
struct employee
{
int number;
float basicpay;
}emp[50];
In the above example emp is an array variable, with each of its element is a structure of type
employee. The each element of the array is referenced with its subscript enclosed in square
brackets followed by a dot operator and the member-name (structure member).
e.g.,
emp[0].number = 110;
emp[0].basicpay = 2500.00;
printf (%f, emp[0].basicpay);
Array within structure:
Sometimes each member of a structure can be array. Consider the following example
struct
{
int regno;
int marks[5];

40

} stud[50];
In the above given example marks is the member of the structure, also it is an array of type
integer and then the structure variable is also an array. Each element of the array variable stud is
referenced with its subscripts enclosed in square brackets followed by a dot operator and the
each element of member (array) is referenced with its subscripts enclosed in square brackets.
e.g.,
stud[0].marks[0] = 64;
stud[0].marks[1] = 694;
stud[0].marks[2] = 81;
stud[0].marks[3] = 84;
stud[0].marks[4] = 55;
In the above examples, the integer values are assigned for marks of the five subjects of first
student of the array.
Pointers to a structure:
Just like any other pointer variable, a pointer variable for structure is defined. For example, with
reference to the structure considered. We may have:
struct employee *sp;
Here, sp is a pointer variable pointing to a structure variable with tag name employee. At this
stage, a memory location for the pointer variable sp is allotted, but its contents are not known.
Hence, sp must be initialized with the address of the structure variable before use.
e.g.,
sp = &emp1;
Note that in structures, the name of a structure is not its address. Hence, the address of the
structure variable must be explicitly obtained with the & operator. This is permissible because
sp is a variable. (In case of an array, the name of an array is a constant.)
The member of the structure pointed to by a pointer variable are accessed with use of the
operator ->
e.g.,
sp ->number = 125
sp ->basicpay = 4500
printf (\n %s, sp->name);
In the above example, the pointer variable sp is pointing towards the members number an
basicpay by the arrow operator (->). Here the pointer variable is directly accessing the members
of the structure, because the address of the structure variable is assigned to the pointer variable.
Nested Structure (Structure within a structure):
It is possible to have a structure in which a member is also another structure. Consider the
following example:
struct measure
{
int feet;
float inches;
};
struct room
{
struct measure l, b;
}r;

41

In the above given example, the structure (room) contains two members l and b. Both l and b are
the variables of the structure type measure. The variable r is the structure of type room, which
has the rights of accessing the members feet and inches through its own members. The access
method is given as follows.
e.g.,
r.l.feet = 3;
r.l.inches = 4.3;
r.b.feet =2;
r.b.inches = 2.1;
UNIONS
Unions, like structures contain members whose individual data types may differ from one
another. However, the members within all share the same storage area within the computers
memory, whereas each member within a structure is assigned its own unique storage area. Thus,
unions are used to conserve memory. They are useful for applications involving multiple
members, where values need not be assigned to all of the members at any one time.
In general terms, the composition of a union may be defined as
storage-class union tag
{
member-1;
member-2;
----member-m;
} variable-1, variable-2, . , variable-n;
Where storage-class is an optional specifier. Union is a required keyword and the other terms
have the same meaning as in a structure definition.
USER-DEFINED data-types:
C is flexible that it allows the user to define new data-type names and they can be subsequently
used in the program. These are called type definitions and they are not new data types but are
derived from the standard data types by renaming them differently.
The following is an example of a new data-type of name mark list, which is derived from a
structure.
typedef struct
{
char name[30];
int rollno;
int marks;
}
marklist;
Now, mark list becomes a data-type name and this can be used to define structure variables st1,
st2 and follows:
marklist st1, st2;
Enumerated Data-type:
Enumeration is a special type of variable, which can take values only a defined list of signed
integer constants. Each of these integer values is given a symbolic name. All these symbolic
names are listed within a pair of braces.

42

The syntax is:


enum tag-name {member-1, member-2, .. , member-k};
The keyword enum is followed by the tagname. The symbolic names member-1, member-2,
..,member-k are correspond to signed integer constants:
e.g.,
enum cards {dice, hearts, clef, spade};
The variable cards is an enumerated data-type. The names listed are the only 4 values it can
take.
In the absence of initialization, C assigns automatically values, by default, as 0, 1, 2, 3. The user
can change the default assignment of numbers to any desired value. Consider the following:
enum colour { black =1, white, red, green = 5, blue};
The assignment will be as follows:
black =1, white = 2, red = 3, green = 5, blue = 6.
FILES:
Some applications require storing of data permanently and retrieve the stored data as and when
they are needed for processing. Eg: Employee details of a company, students detail, Inventory
information. They are maintained in the form of files. A file may be considered as a sequence of
bytes of data stored on an external storage device. Files are classified as:
Text files
Binary files
depending on how the bytes are interpreted.
Text files:
In text files, each byte is interpreted as an ASCII character corresponding to the integer value
represented in that type. A text file can be read or modified by a text editor. For creation,
reading and writing a text file through a C program, a number of library functions are available.
Binary files:
In a binary file, all the data are stored in their binary representation. Binary files are used for
storing objects and executable forms of programs. They are also ideal for storing numeric data.
In a text file, each digit of a numeric value is stored in one byte as an integer corresponding to its
ASCII code. Hence, each numeric value requires a longer number of bytes for storage in a text
file as compared to that required for the same value stored in a binary file. Functions are
available to read and write binary files.
File Input and Output:
Library Functions:
All the Input / Output are handled only through a set of library functions. They may be classified
as:
Buffered (Stream)
Unbuffered I/O Routines
Buffered I/O or Stream I/O:
In the buffered system, there is a temporary storage are in the memory called buffer. This is
associated with each file when it is opened. The program reads from this buffer or writes into
this buffer. The buffer is the interface between the program and the device. The library
functions cause a block of bytes from the file to be read into the buffer or a block of bytes from
the buffer to be written into the file.

43

In the unbuffered or low-level system there is no buffer between the program and the device.
Read and write operations are done directly between the operating system and the program.
Low-level I/O functions have no formatting capability and are suitable for binary files only.
ANSI C does not provide for low-level I/O functions. It has standard functions defined only for
stream or buffered I/O.
Stream I/O Functions:
The function prototype for each of the stream I/O function is declared in the header file stdio.h.
Hence, this header file must be included in any C program, whenever any of these routines is to
be used.
The functions related to input from the keyboard and output to the monitor are discussed already.
They are:
Getchar putchar gets puts printf scanf vprintf
The functions sprintf sscanf vsprintf
Are concerned with formatted strings.
Routines connected with file I/O are:
Only one byte is read or written at a time. Routines available are: fgetc fputc getc putc ungetc
Line reading or writing:
Here, each line ending with a new line character is read or written as a string at a time. The
functions available are: fgets fputs
Formatted Reading or Writing:
Here, a group of related data, which can be a combination of different data types is read or
written together. The functions available are:
Fscanf fprintf vfprintf
Binary Read or Write:
They are also known as record read or write. The data stored in a record is full is read or written
in a single use of the functions. They are used with structures. The functions are:
fread fwrite
Other routines related to file management:
Opening and Closing of files:
Fopen freopen fclose fflush
Getting and Setting read / write positions:
Ftell fgetpos fseek fsetpos rewind
File Structure:
A data file is generally initialized as consisting of a number of record, with each record
comprising a number of fields of related items. Each field in a record may contain a different
type of data. The records in a file may be of the same length (fixed length record) or each record
any of a different length. (Variable length record file)
The functions listed earlier can be used with both variable and fixed length record files. For
dealing with variable length record files, field separators between adjacent fields should be
present.
Opening and Closing of files:
File Pointers:
There is a special data structure called FILE type, defined in the header file stdio.h. In a C
program, all files are referred through file pointers. A file pointer is a pointer variable of the type
FILE. The syntax for defining a file pointer variable is:
FILE *fp;

44

fp is the pointer variable. The datatype pointed to by fp correspond to FILE type. Whenever a
file is opened by a stream I/O functions such as fopen(), a pointer to the FILE structure
associated with that file is returned. In all subsequent operations on this file in the program, all
stream I/O functions refer to that file by this file pointer only.
Opening a file:
Before performing any operation on a file, it must be opened. The library function fopen() is
utilized for this purpose. The syntax is
filepointer = fopen(filename, mode);
Before making a call, the variable file pointer must have been defined as
FILE *filepointer;
There are two arguments for the function:
A string of characters for the name of the file.
A string of character for the mode of using the file.
The values of the two arguments may be given, enclosed in double quotes or they may be given
in the form of pointers to two strings.
The functions fopen() returns a pointer which is assigned to the pointer variable file pointer. If a
file cannot be opened or there is an error in opening the file, it returns a null value. A valid file
pointer cannot have this value. Each file opened will have a separate file pointer.
The string for the mode of using the file, to be given, as an argument for fopen shall be one of the
following:
r Open an existing text file for reading.
w Create a new text file for writing.
a Open an existing text file for appending.
r+ Open an existing file for both reading and writing, starting at the beginning of the file.
w+ Create a new text file for both reading and writing.
a+ Open an existing text file for both reading and appending.
If a binary file is to be used for the above six operations, the character b must be appended to the
mode string as:
rb wb ab r+b w+b a+b
Closing a file:
Every file opened must be closed when the program no longer requires it. This is accomplished
by using the function fclose() which is of the form:
fclose(fp);
Here fp is the name of the file pointer variable associated with the file that is to be closed.
Closing a file causes the data remaining in the buffer to be written to the file. Further, it updates
the directory entry for the files and frees the file pointer. Non-closure of a file may result in
errors, such as loss of data or corruption of the file.
The fclose() function returns an integer. The value returned is 0 if the close operation was
successfully performed; otherwise a non-zero value is returned.
The function freopen() is used to open another file with the same file pointer, closing the current
file associated with that pointer. It has the syntax:
freopen(new file name, fp);
Here, fp is the file pointer associated with a file already opened.
Generally, this file is used to re-direct stdout to a file instead of the usual destination, viz the
monitor.

45

/*Program for Sequential File Creation*/


#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
struct stud
{
int regno;
float avg;
char name[30];
}x;
char c = y;
FILE *f;
clrscr();
F = fopen(Enter the regno :);
while(c == y || c == Y)
{
scanf(%d,&x.regno);
fflush(stdin);
printf(\nEnter the name :);
scanf(%sx.name);
printf(Enter the average :);
Scanf(%f,&x.avg);
fflush(stdin);
printf(Do you wish to add one more record (y/n) :);
scanf(%c,&c);
fprintf(f,%5d%30s%6.2f,x.regno,x.name,x.avg);
}
fclose(f);
}
/*Program for processing a sequential file*/
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
struct stud
{
int regno;
float avg;
char name[30];
}x;
FILE *f;
clrscr();

46

f = fopen(stud.dat, r);
while(!feof(f))
{
fscanf(f, %d%s%f,&x.regno,&x.name,&x.avg);
printf(Name : %30s\n,x.name);
printf(Regno :%5d\n,x.regno);
printf(Average :%6.2f\n,x.avg);
}
fclose(f);
getch();
}
/*Program for Random File Creation*/
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
struct stud
{
int regno;
float avg;
char name[30];
}x;
char c = y;
FILE *f;
clrscr();
f = fopen(stud1.dat, w);
while(c = = y || c = = Y)
{
printf(Enter the Regno :);
scanf(%d, &x.regno);
fflush(stdin);
printf(Enter the Name :);
scanf(%s,x.name);
printf(Enter the Average :);
scanf(%f,x.avg);
fflush(stdin);
printf(Do you wish to add one more :);
scanf(%c, &c);
fwrite(&x, sizeof(x), 1, f);
}fclose(f);
}
/*Program for Processing the Random File*/
#include<stdio.h>

47

#include<conio.h>
#include<string.h>
void main()
{
struct stud
{
int regno;
float avg;
char name[30];
}x;
FILE *f;
clrscr();
f = fopen(stud1.dat, r);
while(!feof(f))
{
if(fread(&x,sizeof(x),1,f) = = 0)
break;
printf(Name :%30s\n,x.name);
printf(Regno :%5d\n,x.regno);
printf(Average : %f\n, x.avg);
}
fclose(f);
getch();
}

48

You might also like