Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Programming in C

Download as pdf or txt
Download as pdf or txt
You are on page 1of 65

Programming in C

UNIT-I
Arrays
Definition, declaration and initialization of one dimensional array; Accessing array elements;
Displaying array
elements; Sorting arrays; Arrays and function; Two- Dimensional array: Declaration and
Initialization,
Accessing and Displaying, Memory representation of array [Row Major, Column Major];
Multidimensional array

UNIT-II
Pointers
Definition and declaration, Initialization; Indirection operator, address of operator; pointer
arithmetic; dynamic
memory allocation; arrays and pointers; function and pointers

UNIT-III
Strings
Definition, declaration and initialization of strings; standard library function: strlen(), strcpy(),
strcat(), strcmp();
Implementation without using standard library functions

UNIT-IV
Structures
Definition and declaration; Variables initialization; Accessing fields and structure operations;
Nested structures;
Union: Definition and declaration; Differentiate between Union and structure

UNIT-V
Introduction C Preprocessor
Definition of Preprocessor; Macro substitution directives; File inclusion directives; Conditional
compilation
Bitwise Operators
Bitwise operators; Shift operators; Masks; Bit field

UNIT-VI
File handling
Definition of Files, Opening modes of files; Standard function: fopen(), fclose(), feof(), fseek(),
fewind(); Using text files: fgetc(), fputc(), fscanf() ,Command line arguments

Reference Books:
1. Let us C-Yashwant Kanetkar.
2. Programming in C-Balguruswamy
3. The C programming Language – Dennis Ritchie
4. Structured programming approach using C-Forouzah & Ceilberg Thomson learning Publication.
ARRAY
An array is a series of elements of the same type placed in contiguous memory locations that
can be individually referenced by adding an index to a unique identifier.
An array is a data structure of multiple elements with the same data type. The values in an
array is called as 'elements of an array.' Array elements are accessed using subscript. The
valid range of subscript is 0 to size -1.
' Arrays may be of any variable type. Array is also called as 'subscripted variable.'

Types of an Array :

1. One / Single Dimensional Array


2. Two Dimensional Array / Multi Dimensional

Single / One Dimensional Array :


The array which is used to represent and store data in a linear form using only one subscript and
such a variable is called as 'single or one dimensional array.'

Declaration of an One Dimensional Array


Arrays must be declared before they can be used in the program. Standard array declaration is
as

< data type > < variable_name > [length-of-array];

Here <data type> specifies the variable type of the element which is going to be stored in the
array.

You must follow the rules below when you declare an array in C:

 The data type can be any valid C data types including C structure and union.
 The name of an array has to follow the rule of C variables.
 The size of array has to be a positive constant integer (Non-zero).

Example :

int list[5];
char str[20];
float salary[10];

Initializing Arrays
It is like a variable, an array can be initialized. To initialize an array, you provide initializing
values which are enclosed within curly braces in the declaration and placed following an equals
sign after the array name.
Syntax:

<data type> array_name[size_of_array] = {element 1, element 2, ...};

Here is an example of initializing an array.

int list1[5] = {2,1,3,7,8};


int list2[5] = {2,1,3};
char ch[20] = "MICROTEK";
float stax[3] = {5003.23, 1940.32, 123.20};
Total Size of Array (in Bytes):

total size = length of array * size of data type ;

Array and Pointer


An array is a pointer to the 0th element of the array. When you dereference the array name you
will get the 0th element. This give us the possibility of accessing array's element not only via
index but also via pointer.

It is note that the array is treated as constant so you can only modify the values in the array but
not array itself.

Memory Representation of Array:


int Arr[5]={ 4 , 7 , 8 , 9 , 3 };

it will allocate memory as:

Arr[0] Arr[1] Arr[2] Arr[3] Arr[4] Notation

[0] [ 1 ] [ 2 ] [ 3] [4] index No.


(Subscript)
Arr Values
4 7 8 9 3
Memory Addresses 1001 1003 1005 1007 1009

Base Address

The Memory address is allocated randomly so that it’s not fixed. It may be any Address

Declared at the time of allocation.

Accessing Array Element


Once an array is declared, individual elements can be accessed using subscript or index
number. this specifies the element’s position in the array.
You can access array elements via indexes like array_name[index No.].
Thus array[4] is actually the fifth element of the array.
Entering Data into an Array
int a[7], i=0;
printf("Enter the elements of the array :");
for (i=0;i<=6 ;i++ )
{
scanf("%d\n", &a[i]); /* taking input array from the user */
}

Reading Data from an Array


printf("\nThe elements of the array you have entered are as follows :")
for(i=0; i<=6; i++)
{
printf("%d", a[i]); /* printing the array elements or traversing the array */
}

Example:
#include<stdio.h>
#include<conio.h>
void main()
{
int array[5]={1,3,5,8,12};
int i ;
clrscr();
for(i=0;i<5;i++)
{
printf(“Enter Element at %d index :”,i);
scanf(“%d”,&array[i]);
}

printf(“\nYour Elements of array are :\n”);


for(i=0;i<5;i++)
{
Printf(“The Value at Index [%d] is = %d\n”, i , array[i]);
}
getch();
}
Output :
Enter Element at 0 index : 1
Enter Element at 1 index : 3
Enter Element at 2 index : 5
Enter Element at 3 index : 8
Enter Element at 4 index : 12

Your Elements are:

The Value at Index [0] is = 1


The Value at Index [1] is = 3
The Value at Index [2] is = 5
The Value at Index [3] is = 8
The Value at Index [4] is = 12
Two Dimensional Array :
it is possible to have an array of more than one dimension. Two dimensional arrays (2-D
arrays) is an array of number of one-dimensional arrays. Two Dimensional Array have two
index no.

First is Row index and second is Column index. Row index specifies Array number which
you want to use and Column index specifies the column number of array which you specified
by row index.

A two dimensional array is also called a matrix.


General form of declaring 2-D array is
data_type array_name [ row size ] [column size] ;

where row size specify the number of array and column size specify the size of each array.
Example:
int array1[3][3];
float mat2 [3][4];

Initializing 2-D Arrays


It is like a variable, an array can be initialized. To initialize an array, you provide initializing
values which are enclosed within curly braces in the declaration and placed following an equals
sign after the array name.

Syntax:

<data type> array_name[size_of_row] [size_of_col ] = {element 1, element 2, ...};

OR

<data type> array_name[size_of_row] [size_of_col ] = { {element 1, element 2, ...},

{element 1, element 2, …},


.
.
.
};

Here is an example of initializing an 2-D array of integers.

int list1[3][3] = {2,1,3,7,8,4,5,6,9};


int list2[2][2] = { {2,1},
{3,5} };
the values are missing in an initializer, they are automatically set to O. For instance,
The statement,

static int table [2] [3] = {{1, 1}, {2} };


will initialize the first two elements of the first row to 1, the first element-of the second row to 2, and all other
elements to 0.
When all the elements are to be initialized to 0, the following shortcut method may be used.
static int m [3] [5] = {{0}, {0}, {0}};

The first element of each row is explicitly initialized to 0 while other elements are
automatically initialized to o.

While initializing an array it is necessary to mention the second (column dimension,


whereas the first dimension (row) is optional. Thus the following declarations are acceptable.
static int arr [2] [3] = {12, 34, 23, 45, 56, 45};
static int arr [ ] [3] = {12, 34, 23, 45, 56, 45 };

Memory Representation of 2-D Array:


In the memory, whether it is a one dimensional or a two dimensional array, the array _

elements are stored in one continuous chain.

Example: int array[3][3]


Row index 0 1 2

Column index 0 1 2 0 1 2 0 1 2
array [0][0] [0][1] [0][2] [1][0] [1][1] [1][2] [2][0] [2][1] [2][2]

Memory Address 101 103 105 107 109 111 113 115 117 .

Logically we can represent 2-D Array as form of matrix:

Column Index

0 1 2
array 0 [0][0] [0][1] [0][2]
Row Index
1 [1][0] [1][1] [1][2] Notation
2 [2][0] [2][1] [2][2]
Example : Read Numbers in 3*3 matrix and print it.
#include <stdio.h>
#include <conio.h>
void main()
{
int a[3][3], i, j;
clrscr();
printf("\n\t Enter matrix of 3*3 : ");
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
{
scanf("%d",&a[i][j]); //read 3*3 array
}
}
printf("\n\t Matrix is : \n");
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
{
printf("\t %d",a[i][j]); //print 3*3 array
}
printf("\n");
}
getch();
}

Output :

Enter matrix of 3*3 : 3 4 5 6 7 2 1 2 3

Matrix is :
3 4 5
6 7 2
1 2 3

Multi-Dimensional Arrays:
C allows arrays of three or more dimensions. Multi-dimensional arrays are defined in
much the same manner as one dimensional arrays, except that a separate pair of square
Brackets are required for each subscript.
The general form of multi-dimensional array is

data_type array_name [s1] [s2] [s3] ....... [sn];


Example:
int survey [3] [5] [12];
float table [5] [4] [5] [3];

Here, the survey is a three dimensional array declared to contain 180 integer type
elements. Similarly, table is a-four dimensional array containing 300 elements of floating point
type.

An example of initializing a three dimensional array:

static int arr [3] [4] [2] = {

{ {2, 4}, {7, 8}, {3, 4}, {5, 6}, },


{ {7, 6}, {3, 4}, {5, 3}, {2, 3}, },
{ {8, 9}, {7, 2}, {3, 4}, {6, 1}, }
};
In this example, the outer array has three elements, each of which is a two dimensional
array of four rows-each of which is a one dimensional array of two elements.

Logically we can represent a three dimensional array as:


Example: int array [ 3 ] [ 4 ] [ 5 ];

No. of Matrix Row-Size of Matrix Column-Size of matrix


M
A 2
T
R
I 1
X
0
I
N
D
E
X

Passing Array to a function :


Array elements can be passed to a function by calling the function by value, or by reference.
In call by value, we pass values of array elements to the function while in call by reference
we pass the name of array, without any subscript, and the size of array elements to the
function. Because array name is constant pointer that hold base address of first element
(array[0]).

Example :

/* passing Array by value * /

#include<stdio.h>
#include<conio.h>

void display(int); // function prototype

void main( )
{
int array[5]={2,4,6,8,9};
int i;
clrscr();
for(i=0;i<5;i++)
{
display(array[i]); // passing each array’s element one by one
}
getch();
}

void display(int n) //receive element in n


{
printf(“%d\t”,n);
}
Example :

/* passing Array by Reference * /

#include<stdio.h>
#include<conio.h>

void display( int[ ] ); // function prototype

void main( )
{
int array[5]={2,4,6,8,9};
int i;
clrscr();
display(array); // passing base address of array
getch();
}

void display(int n[] ) //receive element in array n


{
int i;
for(i=0;i<5;i++)
{
printf(“%d\t”,n);
}
}

Functions Returning values


The result of the function can be returned to the calling program. This defines the type-
specifier in the function header. By default in C each function has a return type of "int". A
function can return only one value. Arguments- are passed by reference to overcome this
limitation.
If you want the function to return a value of any other data type than the default,
you need to mention it explicitly in the function header (prototype).
The following example illustrates this
Example :

/* finding largest value in an array * /


#include<stdio.h>
#include<conio.h>

int large( int[ ] ); // function prototype


void main( )
{
int array[5]={2,4,6,8,9};
int i,max;
clrscr();
max=large(array); //receive largest value in max returned by large( ) function
printf(“Largest value =%d”, max);
getch();
}

int large(int n[] ) //receive element in array n


{
int i,m=n[0];
for(i=1;i<5;i++)
{
If( m <n[ i ])
m=n[ i ];
}
return m; //return value of m
}
Introduction to pointers
A pointer is a variable that stores memory address. It is called pointer because it points to a
particular location in memory by storing the address of that location.
This variable may be type of void, int, char, array, structure, function or any other pointers.
It is a variable which can hold the address of a memory location rather than the
value at the location.

Whenever we declare a variable, the system allocates, somewhere in the memory, a memory
location and a unique address is assigned to this location.

Consider the following statement

int num=84;
This statement instructs the system to reserve a 2-byte memory location and put the
value 84 in that location.

num Variable Name

84 Value

65524 Address of memory location

Let ptr be a variable which holds the address of a variable num.


Thus, we can access the value of num by the variable ptr. We can say "ptr” points to “num”.
It can be represent as-

num ptr

84 65524
65524

Pointer Notation
The actual address of a variable is not known immediately. We can determine the address
of a variable using "address of” operator (&). Another pointer operator available in C is "*"
called "value at address" operator. Which gives the value stored at a particular address.
This operator is also known as "indirection operator".
Example :
void main( )
{
int Num=10;
clrscr( );
printf(“Address of Num = %u”,&Num);
printf(“The Value of Num = %u”,*(&Num));
getch();
}
Explanation:
Variable Num allocate 2 bytes in memory and store 10 at that location, as

Num 10 *(&Num)
&Num 65524
Where expression “&Num” give Memory address and “*(&num)” give value at
address of Num.

Pointer Declaration and Initialization


Declaring a pointer variable is quite similar to declaring a normal variable all you have to do is
to insert a star '*' operator before it.

General form of pointer declaration is -

data_type* ptr_name;

This tells the compiler three things about the variable ptr_name .
 The asterisk (*) tells that the variable ptr_ name is a pointer variable.
 ptr_name needs a memory location.
 ptr_name points to a variable of type “data _type”.

Example: int *p;


Declares the variable p as a pointer variable that points to an integer data
type. The type int refers to the data type of the variable being pointed to
by p and not the type of the value of the pointer.

Once a pointer variable has been declared, it can be made to point to a variable using
an assignment statement such as p = &quantity; which causes p to point to quantity.
That is, p now contains the address of quantity. This is known as pointer initialization.
Before a pointer is initialized, it should not be used.

Example: Num P
int Num=100;
100 65524
int *p=&Num;
65524

Accessing Variable through Pointer

Consider the following Example.

#include<stdio.h>
#include<conio.h>
void main()
{
int x=100;
int *p = &x;
/* displays address of x */
printf (“\n%u\t%u”, &x,p);
/* displays value at x */
printf (“\n%d\t%d”, x, *p);
/* displays address of p */
printf (“\n&p=%u”, &p);
getch();
}
Output :
65428 65428
100 100
65426

Pointer Expressions
Like other variables, pointer variables can be used in expressions. Arithmetic and comparison
operations can be performed on the pointers.
Example: If p1 and p2 are properly declared and initialized pointers, then following
statements are valid.

y = *p1 * *p2;
sum = sum + * p1;
Example:
#include<stdio.h>
#include<conio.h>
void main()
{
int a=20,b=30,sum1,sum2;
int *p1,*p2;
p1= &a; //store address of a in p1
p2= &b; //store address of b in p2
sum1= a + b;
sum2= *p1 + *p2;
printf(“Value of sum1=%d\nValue of sum2=%d”,sum1,sum2);
getch();
}

Output:
Value of sum1=50
Value of sum2=50

Pointer Arithmetic
C allows us to add integers to pointers as well as subtract one pointer from another.
Shorthand operators like sum + = *p2; can also be used with the pointers for arithmetic
expressions. Following operations can be performed on a pointer:
Not all arithmetic operations are defined in pointers. You can increment them, decrement
them, add and subtract integer values from them. You even can subtract two pointers,But
you cannot add two pointers, multiply, divide, modulus them. You can not also add or
subtract values other than integer.

Example 1:
#include<stdio.h>
int main()
{
int *ptr=( int *)1000;
ptr= ptr +1;
printf("%u",ptr);
getch();
}
Output:= 1002
Example 2:

#include<stdio.h>
int main()
{
double *p=(double *)1000;
p=p+3;
printf("%u",p);
getch();
}

Output: 1024

Example 3:

#include<stdio.h>
int main()
{
float array[5]={1.1f,2.2f,3.3f};
float(*ptr)[5];
ptr=&array;
printf("%u\n",ptr);
ptr=ptr+1;
printf(" %u",ptr);
getch();
}

Output: 1000
1020
Example 4:

void main()
{
int i, *j, *k;
i = 4;
j = &i;
k=j+1;
printf (“%u\t%u\t%u”, &i, j, k):
}
Output:

If address of i is 1000 then the output will be

1000 1000 1002


Pointer Increment / Decrement and Scale Factor
The pointers can be incremented as
p1 = p2 + 2;
Similarly, pointers can be decremented as
p1 = p2 - 1;

Shorthand operators can also be used to increment or decrement the pointers.


p1 ++ ;
++ p2 ;
p2 -- ;
-- p2 ;
An expression like
p1 ++;
will cause the pointer pl to point to the next memory location of its type.
For example, if p1 is an integer with an initial value 1000, then after the operation
p1 =p1 + 1, the value of p1 will be 1002. That is, when we increment a pointer, its value
is increased by the length of the data type that it points to.
This length is called the “scale factor”.

Pointer comparison
pointers can be compared using relational operators. Expressions such as pl > p2, p1 = = p2
and
p1 ! = p2 are allowed. Such comparisons are useful when both pointer variables point to
elements of the same array.
Any comparison of pointer that refers to separate and unrelated variables makes no
sense. Comparisons can be used meaningfully in handling arrays and strings.
Example:
#include <stdio.h>
void main ()
{
int data[5]={2,3,5,7,1};
int* p1;
int *p2;

p1 = &data [1];
p2 = &data [2];

if (p1 > p2)


{
printf ("\n\n p1 is greater than p2");
}
else
{
printf ("\n\n p2 is greater than p1");
}
}
Pointers and One Dimensional Arrays
In C language, pointers and arrays are closely related. We can access the array elements using
pointer expressions. Actually the compiler also accesses the array elements by converting
subscript notation to pointer notation. Following are the main points for understanding the
relationship of pointers with arrays.

1. Elements of an array are stored in consecutive memory locations.


2. The name of an array is a constant pointer that points to the first element of the array,
i.e. it stores the address of the first element, also known as the base address of array.
3. According to pointer arithmetic, when a pointer variable is incremented, it points to the
next location of its base type.

If we declare p as an integer pointer, then we can make a pointer to point to the


integer array by the assignment statement as follows:
If p is a pointer to an integer and x is an array then
p = x ; which is equivalent to p = &x[O];

Example :
int X[5]={2,5,7,8,9};
int *P = X; // or int *P=&X[0];

0 1 2 3 4
X 2 5 7 8 9

100 102 104 106 108


P
100

Now we can access every value of array Xusing P+ + to move from one element to another.
The relationship between p and x is shown below:
Expression Result Expression Result Expression Result
&X[0] 100 P 100 *P 2
&X[1] 102 P+1 102 *(P+1) 5
&X[2] 104 P+2 104 *(P+2) 7
&X[3] 106 P+3 106 *(P+3) 8
&X[4] 108 P+4 108 *(P+4) 9

The address of an element is calculated using its index and the scale factor of the
data type.

Example: Address of x[3] = Base Address + (3 * Scale Factor of int)


= 100 + (3 * 2)
= 100 + 6
= 106
Example :
# include<stdio.h>
#include<conio.h>
void main()
{
int array[5]={3,5,6,7,9} ;
int i;
int *P=array; //store the base address to pointer variable P
clrscr( );
printf(“Array Elements using pointer :”);
for(i=0;i<5;i++)
{
printf(“\t%d”, *(P+i));
}
printf(“Array Elements using pointer Arithmetic:”);
for( ;P< P+5 ; P++)
{
printf(“\t%d”, *P);
}
getch();
}
Output : Array Elements using pointer : 3 5 6 7 9
Array Elements using pointer Arithmetic: 3 5 6 7 9
Pointer to an Array / Pointers and Multi-Dimensional Arrays

We can also declare a pointer that can point to the whole array instead of only one element of
array. This pointer is useful when talking about multidimensional arrays.
Declaring a pointer to an array:
data_type (*ptvar) [expression2];
rather than,
data_type array [expression1] [expression2];

This can be generalized to higher dimensional arrays, that is,


data_type (*ptvar) [expression2] [expression 3]…………[expression N];
replaces,
data type array [expression1] [expression2]………. [expression N];

Example :
Suppose X is a two dimensional integer array that has 10 rows and 20 columns.
We can declare X as :
int (*X) [20]; rather than int X[10] [20];

In the first declaration, x is defined to be a pointer to a group of contiguous, one dimensional,


20-element integer arrays. Thus, x points to the first 20-element array, which is actually the
first row (row 0) of the original two dimensional array. Similarly, (x + 1) points to the second
20-element array, which is the second row (row 1) of the original two dimensional array, and
so on.
Note that it is necessary to enclose the pointer name inside parentheses. Here the type of X is
‘pointer to an array of 20 integers’.
Note:- The pointer that points to the 0th elements of array and the pointer that points to the
whole array are totally different.

First One Dimensional Array


X

Second One Dimensional Array


(X+1)

Third One Dimensional Array


(X+2)
.
. *(X+2) *(*(X+2)+5) *(X+2)+14
. Nth One Dimensional Array
(X+9)
The following program shows this–

/* Program to understand difference between pointer to an integer and pointer to


an array of integers */

#include<stdio.h>
void main()
{
int *p; /* Can point to an integer */
int (*ptr) [5]; /* Can point to an array of 5 integers */
int arr[5];
p=arr; /* Points to 0th element of arr */
ptr=arr; /* Points to the whole array arr */
printrf(“p = %u, ptr = %u\n”, p, ptr);
p++;
ptr++;
printf(“p = %u, ptr = %u\n”, p, ptr);
getch();
}

Output:-
P = 3000, ptr = 3000
P = 3002, ptr = 3010

Arrays of Pointers
We can declare an array that contains pointers as its elements. Every element of this array is a
pointer variable that can hold address of any variable of appropriate type. The syntax of
declaring an array of pointers is similar to that of declaring arrays except that an asterisk is
placed before the array name.

datatype *arrayname[size];

For example
to declare an array of size 10 that contains integer ponters
we can write-
int *arrp[10];
main()
{
int * pa[3];
int i,a=5,b=10,c=15;
pa[0]=&a;
pa[1]=&b;
pa[2]=&c;
for(i=0;i<3;i++)
{
printf(“pa[%d]=%u\t”,i , pa[i]);
printf(“*pa[%d]=%u\n”, i , *pa[i]);
}
}

Output:
pa [0] =2012 *pa[0]=5
pa[1]=2560 *pa[1]=10
pa[2]=3020 *pa[2]=15
Here pa is declared as an array of pointers. Every element of this array is a pointer to an
integer. pa[i] gives the value of the ith element of ‘pa’ which is an address of any int variable
and *pa[i] gives the value of that int variable.

Arrays of Pointer as Two or Multi dimensional array

Suppose that X is a two dimensional integer array having 10 rows and 20 columns,
we can define x as a one dimensional array of pointers by writing

int *X[10];
Hence, X[O] points to the beginning of the first row, X[1] points to the beginning of the
second row, and so on. The number of elements within each row is not explicitly specified.

An individual array element, such as X[2][5], can be accessed by writing *(X[2] + 5).
in this expression, x[2) is a pointer to the first element in row 2, so that (x[2] + 5) points to
element 5 (actually, the sixth element) Within row 2. The object of this pointer, *(x[2] + 5);
therefore refers to x[2][5].
This can be explained by following figure:

X First One Dimensional Array


0 3324
3324 3326 … …. …. …. ….. …. …. …. …. 3344 ……
1 6320
Second One Dimensional Array
2 4210

3 .
6320 6322 … …. …. …. ….. …. …. …. …. 6340 ……
4 .
5 .
Third One Dimensional Array
6 .

4210 7 . 4212 … …. …. …. ….. …. …. …. …. 4230 ……


. 8 .
. *(X+2) *( X[2] + 6 ) ( X[2] + 9 )
. 9 9228
.
Nth One

Dimensional Array

9228 9230 … …. …. …. ….. …. …. …. ….. 9248 …

Pointer to Pointers

Pointer is a variable which contains address of a variable. This variable itself could be
another pointer. Declaration of such variables requires increase in number of "*"
(the indirection operator) as prefix to the variable name.

For example:
int N=100;
int *P1=&N;
int **P2=&P1;

We have a pointer ‘p2’ that points to yet another pointer ‘p1’ that points to a integer ‘N’.
In memory, the three variables can be visualized as-
P2 P1 N

55636 62342 100


65524 55636 62342

Address of P1 Address of N Value

The following expression gives result after printing.

Expression Output Expression Output


P1 62342 P2 55636
*P1 100 *P2 62342
*(&N) 100 **P2 100
*(&P1) 62342 *(*(&P2)) 62342

*(*(&P1)) 100 *(*(*(&P2))) 100

Example :

#include<stdio.h>

void main(void)
{
char **ptr = NULL;
char *p = NULL;
char c = 'd';
p = &c;
ptr = &p;
printf("\n c = [%c]\n",c);
printf("\n *p = [%c]\n",*p);
printf("\n **ptr = [%c]\n",**ptr);
getch();
}

Here is the output :

c = [d]
*p = [d]
**ptr = [d]

Pointers and Functions


One of the best things about pointers is that they allow functions to alter variables outside of
their own scope. By passing a pointer to a function you can allow that function to read and
write to the data stored in that variable.
Example :
#include<stdio.h> #include<stdio.h>
#include<conio.h> #include<conio.h>
void swap(int *px, int *py) // receive in int pointer void swap(int px, int py) // receive in int variable
{ {
int temp; int temp;
temp = *px; temp = px;
*px = *py; px = py;
*py = temp; py = temp;
} }
void main() void main()
{ {
int A=10,B=20; int A=10,B=20;
clrscr(); clrscr();
printf(“Before Calling swap function:\n”); printf(“Before Calling swap function:\n”);
printf(“Value of A=%d\n”,A); printf(“Value of A=%d\n”,A);
printf(“Value of B=%d”,B); printf(“Value of B=%d”,B);
swap(&A,&B); // passing address of A and B swap(A,B); // passing Value of A and B
printf(“\nAfter Calling swap function:\n”); printf(“\nAfter Calling swap function:\n”);
printf(“Value of A=%d\n”,A); printf(“Value of A=%d\n”,A);
printf(“Value of B=%d”,B); printf(“Value of B=%d”,B);
getch(); getch();
} }

Output : Output :

Before Calling swap function: Before Calling swap function:


Value of A=10 Value of A=10
Value of B=20 Value of B=20

After Calling swap function: After Calling swap function:


Value of A=20 Value of A=10
Value of B=10 Value of B=20
Functions Returning pointers
A function can return a pointer just as it returns an int, a float, a double, or any other data
type.
To make a function return a pointer it has to be explicitly mentioned in the calling
function as well as in the function declaration. The following program illustrates this.
Example :

void main()
{
int * func(); // Function prototype that have return type “ int * ”
int *p;
p=func( ); // Receiving address of variable N
printf(“Pointer p points the value :%d”,*p);
getch();
}

int * func()
{
int N=1000;
return (&N); // returning Address of N
}

Output :
Pointer p points the value: 1000

Pointers to Functions
A function, like a variable, occupies memory and has a unique address to that location
(The starting address).
A pointer to a function points to the address of the executable code( starting address)
of the function. You can use pointers to call functions and to pass functions as
arguments to other functions. You cannot perform pointer arithmetic on pointers to
functions.

Declaring and Initializing a Function pointer

A function pointer can be declared as:

<return type of function> (*<name of pointer>) (type of function arguments);

For example :

int (*fptr) (int , int)

The above line declares a function pointer ‘fptr’ that can point to a function whose return type is
‘int’ and takes two integers as arguments.

Let’s take a working example:


#include<stdio.h>

int func (int a, int b)


{
printf("\n A = %d\n",a);
printf("\n B = %d\n",b);
return 0;
}

void main(void)
{
int(*fptr)(int,int); // Function pointer

fptr = func; // Assign address to function pointer


printf(“Calling function through Function name:\n”);
func(2,3);
printf(“Calling function through Function Pointer:\n”);
fptr(20,30); // or (*fptr) (20,30);
getch( );
}

Output :
Calling function through Function name:
A=2
B=3
Calling function through Function Pointer:
A=20
B=30
String
Just as the group of integers can be stored in an integer array, the group of characters
can be stored in a character array or "strings". The string constant is a one dimensional array
of characters terminated by “null” character (‘\0'). This null character \0' (ASCII, value 0) is
different from '0' (ASCII value 48).
C does not have a string type as other modern programming languages. C only has
character type so a C string is defined as an array of characters or a pointer to characters.

The terminating null character is important because it is the only way the function
that work with string can know where the string ends.

Example :
static char str[ ]= { ‘S’,’A’,’B’,’A’,’B’,’\0’};
char str[]=”SABAB”;

This example shows the declaration and initialization of a character array. The array
elements of a character array are stored in contiguous locations with each element occupying
one byte of memory.
NULL Character

Index Number 0 1 2 3 4 5

Element ‘S’ ‘A’ ‘B’ ‘A’ ‘B’ ‘\0’

Memory Address 4001 4002 4003 4004 4005 4006

Read Strings from keyboard:

To read a string, we can use scanf() function with format specifier %s.

char name[50];
scanf("%s",name);
The above format allows accepting only string which does not have any blank space, tab, new line,
forming feed, carriage return.

Write Strings on Console:

To write a string, we can use printf() function with format specifier %s.

char name[50];
scanf("%s",name);
printf("%s",name);

You can access individual element ( character ) of a string by using a subscript. Here is an
example of accessing individual element of string using a subscript (index no.):
#include<stdio.h>
#include<conio.h>
void main()
{
char str[20];
int i;
clrscr();
printf(“Enter any String :”);
gets(str); // or you can use printf(“%s”,str);
printf(“Your String are :”);
for(i=0;str[i]!=’\0’;i++)
{
printf(“\n%c”,str[i]);
}
getch();
}

Output :

Enter any String : MICROTEK


Your String are :
M
I
C
R
O
T
E
K

Library functions For Handling String operations:


Strings, both constant and variable, may be manipulated without using the standard library.
However, the library contains many useful functions for working with null-terminated strings.
It is the programmer's responsibility to ensure that enough storage has been allocated to hold
the resulting strings.

The most commonly used string functions are:


Function Use
int strlen(char *str) Finds length of a string
char * strlwr(char *str) Converts a string to lowercase
char * strupr(char * str) Converts a string to uppercase
char * strcat(char *d , char *s) Appends one string (s) at the end of another (d)
char * strncat(char *d, char *s, size_t n) Appends first n characters of a string (s) at the end of another (d)
char * strcpy (char *d , char *s) Copies a string (s) into another (d)
char * strncpy(char *d,char *s, size_t n) Copies first n characters of one string (s) into another (d)
Compares two strings (a with b) ; returns negative if a is less than b, 0
int strcmp(char* a , char* b)
if equal, positive if greater.
Compares first n characters of two strings (a with b) ; result same as
int strncmp(char *a, char *b, size_t n)
strcmp()
Compares two strings (a with b) without regard to case ("i" denotes
int stricmp(char* a , char* b)
that this function ignores case) .
Compares two strings (a with b) without regard to case. it is a macro
int strcmpi (char* a , char* b)
that calls stricmp().
int strnicmp (char *a ,char *b , size_t n) Compares first n characters of two strings without regard to case.

char * strdup (char *s) Return Duplicates a string (s)


char * strchr (char *s , int ch) Finds first occurrence of a given character ( ch ) in a string (s)
char * strrchr (char *s , int ch) Finds last occurrence of a given character ( ch ) in a string
char * strstr (char *s1 , char *s2) Finds first occurrence of a given string (s2) in another string (s1)
char * strset (char *s , int ch) Sets all characters of string (s) to a given character (ch)
char * strnset (char *s,int ch , size_t n) Sets first n characters of a string (s) to a given character (ch)
char * strrev (char *s) Reverses string (s)
Structure
A structure is a collection of variables under a single name. These variables can be of
different types, and each has a name which is used to select it from the structure. A structure is
a convenient way of grouping several pieces of related information together.

A structure can be defined as a new named type, thus extending the number of available
types.

Structure is user defined data type which is used to store heterogeneous data under unique
name. Keyword 'struct' is used to declare structure.

The variables which are declared inside the structure are called as 'members of structure'.

Syntax:

struct structure_nm
{
<data-type> element 1;
<data-type> element 2;
- - - - - - - - - - -
- - - - - - - - - - -
<data-type> element n;
}struct_var;

Example :

struct emp_info
{
char emp_id[10];
char nm[100];
float sal;
}emp;

Note :
1. Structure is always terminated with semicolon (;).
2. Structure name as emp_info can be later used to declare structure variables of its type in a
program.

Creating Structure variables


The structure declaration does not actually create variables; instead, it defines data type.
For actual use a structure variable needs to be created. This can be done in two ways:
1) Declaration using tagname anywhere in the program.
Example:
struct book
{
char name [30];
char author [25];
float price;
}
struct book book1, book2;
2) It is allowed to combine structure declaration and variable declaration in one
statement.

This declaration is given below:


struct person
{
char * name;
int age;
char *address;
}
p1, p2, p3;

Structure Initialization

A structure variable can be initialized as any other data type.


void main()
{
static struct
{
int weight;
float height;
} student ={60,168.5};
}
In the above statement student is a variable that holds 60 in weight and 168.5 in
height member.

Memory representation of Structure variable:


Memory Address
1001 1002 1003 1004 1005 1006
weight height Structure Members
Values 60 168.5

2 bytes 4 bytes

It will allocate total 6 byte in Memory (sum of all members’ size).

Comparison of Structure Variables


Two variables of the same structure type can be compared the same way as ordinary
variables.
If person1 and person2 belong to the same structure, then the following operations
are valid.
Operation Meaning

person1 = person2 Assign person2 to person1.

person1 = = person 2 Compare all members of person1 and person2

and return 1 if they are equal, 0 otherwise.

Accessing Structure Members :


Structure members can be accessed using member operator '.' . It is also called as 'dot
operator' or 'period operator'.

structure_var.member_name;

Example 1 :
#include <stdio.h>
#include <conio.h>

struct comp_info
{
char nm[100];
char addr[100];
}info;

void main()
{
clrscr();
printf("\n Enter Company Name : ");
gets(info.nm);
printf("\n Enter Address : ");
gets(info.addr);
printf("\n\n Company Name : %s",info.nm);
printf("\n\n Address : %s",info.addr);
getch();
}

Output :

Enter Company Name : Microtek College of Management


Technology Enter Address : Maldahiya, Varanasi

Company Name : College of Management Technology


Address : Maldahiya, Varanasi

Example 2:
#include <stdio.h>
#include <conio.h>

struct student
{
int id;
char *name;
float percentage;
} ;
student student1;

void main()
{
student1.id=101;
student1.name = "SABAB";
student1.percentage = 97.25;
printf(" Id is: %d \n", student1.id);
printf(" Name is: %s \n", student1.name);
printf(" Percentage is: %.2f \n", student1.percentage);
getch();
}

Output:

Id is: 101
Name is: SABAB
Percentage is: 97.25

Arrays of structures
The most common use of structures is in arrays of structure. To declare an array of structures,
first the structure is defined then an array variable of that structure is declared. In such a
declaration, each element of the array represents a structure variable.
Example:
struct emp
{
int empid;
float salary;
} stud_rec [3];

It defines an array called stud_rec which consist of 3 elements of structure named student.
An array of structures is stored inside the memory in the same way as a multi-
dimensional array.

Index Number (Subcscript )


stud_rec
0 1 2
empid salary empid salary empid salary

1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
2 Bytes + 4 Bytes + 2 Bytes + 4 Bytes + 2 Bytes + 4 Bytes

stud_rec[0].salary stud_rec[1].empid

Total Size of stud_rec is 18 Bytes.

Example:

#include <stdio.h>
#include <conio.h>
struct emp_info
{
int emp_id;
char nm[50];
}emp[2];
void main()
{
int i;
clrscr();
for(i=0;i<2;i++)
{
printf("\n\n Enter Employee ID : ");
scanf("%d",&emp[i].emp_id);
printf("Employee Name : ");
scanf("%s",emp[i].nm);
}
for(i=0;i<2;i++)
{
printf("\n Employee ID : %d",emp[i].emp_id);
printf("\n Employee Name : %s",emp[i].nm);
}
getch();
}
Output :

Enter Employee ID : 101


Employee Name : ABC
Enter Employee ID : 201
Employee Name : XYZ

Employee ID : 101
Employee Name : ABC
Employee ID : 201
Employee Name : XYZ

Array within Structures


Sometimes, it is necessary to use structure members with array.
Single of multi-dimensional arrays of type int or float can be defined as structure members.
Program :

#include <stdio.h>
#include <conio.h>
struct result
{
int rno, mrks[5];
char nm;
}res;
void main()
{
int i,total=0;
clrscr();
printf("\n Enter Roll Number : ");
scanf("%d",&res.rno);
printf("\n Enter Marks of 3 Subjects : ");
for(i=0;i<3;i++)
{
scanf("%d",&res.mrks[i]);
total = total + res.mrks[i];
}
printf("\n Roll Number : %d",res.rno);
printf("\n Marks are :");
for(i=0;i<3;i++)
{
printf(" %d",res.mrks[i]);
}
printf("\n\n\t Total is : %d",total);
getch();
}

Output :
Enter Roll Number : 1
Enter Marks of 3 Subjects : 63 66 68

Roll Number : 1
Marks are : 63 66 68
Total is : 197

Structures within Structures

Structures can be used as structures within structures. It is also called as 'nesting of structures'.
Syntax:

struct structure_nm
{
<data-type> element 1;
<data-type> element 2;
-----------
-----------
<data-type> element n;

struct structure_nm
{
<data-type> element 1;
<data-type> element 2;
-----------
-----------
<data-type> element n;
}inner_struct_var;
}outer_struct_var;

Example 1: Example 2:
struct stud_subj
struct stud_res {
{ char subjnm[30];
int rno; int marks;
char nm[50]; };
char add[10]; OR
struct stud_res
struct stud_subj {
{ int rno;
char subjnm[30]; char nm[50];
int marks; char add[10];
}subj; stud_subj subj; // Another structure type
}result; variable
}result;

Here result is variable of type struct stud_res which have members rno,nm,std and subj.
subj is also a structure variable of type stud_subj. the structure members can be access using dot (.)
operator.

The memory occupied by result variable is shown as:

result
rno nm add subj
subjnm marks

result.rno result.nm result.add result.subj.subjnm result.subj.marks

The Hierarchical representation of result variable is:


result
rno

nm

add

subj
subjnm

marks

Program :
#include <stdio.h>
#include <conio.h>
struct stud_Res
{
int rno;
char std[10];
struct stud_Marks
{
char subj_nm[30];
int subj_mark;
}marks;
}result;
void main()
{
clrscr();
printf("\n\t Enter Roll Number : ");
scanf("%d",&result.rno);
printf("\n\t Enter Standard : ");
scanf("%s",result.std);
printf("\n\t Enter Subject Code : ");
scanf("%s",result.marks.subj_nm);
printf("\n\t Enter Marks : ");
scanf("%d",&result.marks.subj_mark);
printf("\n\n\t Roll Number : %d",result.rno);
printf("\n\n\t Standard : %s",result.std);
printf("\nSubject Code : %s",result.marks.subj_nm);
printf("\n\n\t Marks : %d",result.marks.subj_mark);
getch();
}
Output :

Enter Roll Number : 1

Enter Standard : MCA-I

Enter Subject Code : SUB001

Enter Marks : 63

Roll Number : 1

Standard : MCA-I

Subject Code : SUB001

Marks : 63

Structure Pointers

Pointers can be used to refer to a struct by its address. This is particularly useful for passing
structs to a function by reference. The pointer can be dereferenced just like any other pointer in
C . using the * operator. There is also a -> operator in C which dereferences the pointer to
struct (left operand) and then accesses the value of a member of the struct (right operand).
If you have a pointer to a structure, you use the -> symbol to specify a particular member
rather than the period.

struct point {
int x;
int y;
} my_point;

struct point *p = &my_point; /* To declare p as a pointer of type struct point */

(*p).x = 8; /* To access the first member of the struct */


p->x = 8; /* Another way to access the first member of the struct */
Passing Structures to Functions
These are three methods by which the values of a structure can be transferred from
one function to another.

 The first method is to pass each member of the structure as an actual argument of the
function call. The actual arguments are then treated independently like ordinary
variables.

 The second method involves passing of a copy of the entire structure to the called
function. Since the function is working on a copy of the entire structure to the called
function, changes are not reflected in the original structure (in the calling function). It is,
therefore, necessary for the function to return the entire structure back to the calling
function.

 The third approach employs a concept called pointers to pass the structure as an
argument. In this case, the address location of the structure is passed to the called
function. The function can access indirectly the entire structure and work on it.

Example : 1
typedef struct xyz
{
int roll;
char *name;
}student; /* Here student is duplicate name of struct xyz defined by typedef */

void func1(int r, char *nm); // function declared according to first Method


void func2(student st); // function declared according to second Method
void func3(student &st); // function declared according to third Method
void main()
{
student s={101,”Rahul”};
clrscr();
printf(“\nData stored in structure Member : (Using First method ) \n”);
func1(s.roll,s.name); //passing each member’s value
printf(“\n\nData stored in structure Member : (Using Second method ) \n”);
func2(s); // passing structure
printf(“\n\nData stored in structure Member : (Using Third method ) \n”);
func3(&s); //passing address of structure variable
getch();
}
void func1( int r , char * nm) // receiving each members in separated variable
{
printf(“\nRoll Number : %d”,r);
printf(“\nName : %s”,nm);
}

void func2( student st) // receiving structure in structure variable (copy all member’s)
{
printf(“\nRoll Number : %d”,st.roll);
printf(“\nName : %s”,st.name);
}

void func3( student *st) // receiving structure address in structure pointer st


{
printf(“\nRoll Number : %d”,st->roll);
printf(“\nName : %s”,st->name);
}

Output :

Data stored in structure Member : (Using First method )


Roll Number : 101
Name : Rahul

Data stored in structure Member : (Using Second method )


Roll Number : 101
Name : Rahul

Data stored in structure Member : (Using Third method )


Roll Number : 101
Name : Rahul
Union Definition and Declaration
Unions follow the same syntax as structures. Unions and structures differ in terms of
storage. In structures, each member has its own storage location, whereas all the members
of a union use the same location. This implies that, although a union may contain many
members of different types, it can handle only one member at a time.

Like structures, a union can be declared using the keyword union as follows:

union item
{
int M;
float X;
char CH;
}code;

This declaration declares a variable code of type union item. The union contains three
members, each with a different data type. However, only one can be used at a time.
This is due to the fact that only one location is allocated for it union variable,
irrespective of
its size.

1000 1001 1002 1003 Memory Address


CH
Storage of 4 Bytes M
X

The compiler allocates a piece of storage that is large enough to hold the largest
variable type in the union.

According to the figure, the compiler allocates memory of 4 Bytes from 1000 to 1003.
In which variable
“CH” uses memory location 1000 for only one Byte.
“M” uses memory location 1000,10001 for only two Byte.
“X” uses whole memory location allocated by union 1000,1001,1002 and
1003
for 4 Byte.

The major difference between structure and union is 'storage.' In structures, each member
has its own storage location, whereas all the members of union use the same location. Union
contains many members of different types; it can handle only one member at a time.
Accessing a Union Member
To access a union member, we can use the same syntax that we use for structure members.
For example:
code.M;
code.X;
code.CH
During accessing, we should make sure that we are accessing the member whose value
is
currently stored.

Example :
#include <stdio.h>
#include <conio.h>

union techno
{
int id;
char nm[50];
}tch;

void main()
{
clrscr();
printf("\n\t Enter developer id : ");
scanf("%d", &tch.id);
printf("\n\n\t Enter developer name : ");
scanf("%s", tch.nm);
printf("\n\n Developer ID : %d", tch.id); //Garbage because union can handle only one member at
a time
printf("\n\n Developed By : %s", tch.nm);
getch();
}
Output:
Enter developer id : 101

Enter developer name : Sabab

Developer ID : 25972

Developed By : Sabab
Union of Structures
Just as one structure can be nested within another, a union too call be nested in another
union. Not only that, there can be a union in. a structure, or a structure in a union. Here is
an example of structures nested in a union.

struct student
{
int roll;
char *sname;
};

struct employee
{
int empid;
char *ename;
};

union rec
{
struct student stud; // structure variable of type struct student
struct employee emp; // structure variable of type struct employee
}var; // declare union variable of type union rec

Now, through variable “var” we can use only one structure at a time.
If we write statement,

var.stud.roll=101; var.stud.sname=”Rahul”;
and
var.emp.empid=11001; var.emp.ename=”Sabab”;

then all the record of student will override with employee record.
if we print student record, it will print garbage values.
Preprocessor
The C preprocessor is a program that processes our source program before it is passed
to the compiler. Preprocessor commands (often known as directives) form what can
almost be considered a language within C language. We can certainly write C programs
without knowing anything about the preprocessor or its facilities.

Features of C Preprocessor
The preprocessor offers several features called preprocessor directives. Each of these
preprocessor directives begin with a ‘#’ symbol. The directives can be placed anywhere in
a program but are most often placed at the beginning of a program, before the first
function definition.

We would learn the following preprocessor directives here:

(a) Macro expansion


(b) File inclusion
(c) Conditional Compilation
(d) Miscellaneous directives
Macro Expansion
Have a look at the following program.

#define UPPER 25
main( )
{
int i ;
for ( i = 1 ; i <= UPPER ; i++ )
printf ( "\n%d", i ) ;
}

In this program instead of writing 25 in the for loop we are writing it in the form of UPPER,
which has already been defined before main( ) through the statement,

#define UPPER 25

This statement is called ‘macro definition’ or more commonly, just a ‘macro’. During
preprocessing, the preprocessor replaces every occurrence of UPPER in the program
with 25. Here is another example of macro definition.

#define PI 3.1415
main( )
{
float r = 6.25 ;
float area ;

area = PI * r * r ;
printf ( "\nArea of circle = %f", area ) ;
}
UPPER and PI in the above programs are often called ‘macro templates’, whereas, 25 and
3.1415 are called their corresponding ‘macro expansions’.

When we compile the program, before the source code passes to the compiler it is examined by the C
preprocessor for any macro definitions. When it sees the #define directive, it goes through the entire
program in search of the macro templates; wherever it finds one, it replaces the macro template with
the appropriate macro expansion. Only after this procedure has been completed is the program
handed over to the compiler.

Note that a macro template and its macro expansion are separated by blanks or tabs. A space between
# and define is optional. Remember that a macro definition is never to be terminated by a semicolon.

Example :

#define AND &&


#define OR ||
main( )
{
int f = 1, x = 4, y = 90 ;

if ( ( f < 5 ) AND ( x <= 20 OR y <= 45 ) )


printf ( "\nYour PC will always work fine..." ) ;
else
printf ( "\nIn front of the maintenance man" ) ;
}
A #define directive could be used to replace even an entire
C statement. This is shown below.

#define FOUND printf ( "The Yankee Doodle Virus"


) ; main( )
{
char signature ;

if ( signature == 'Y' )
FOUND
else
printf ( "Safe... as yet !" ) ;
}

Macros with Arguments


The macros that we have used so far are called simple macros.
Macros can have arguments, just as functions can. Here is an
example that illustrates this fact.

Example:

#define AREA(x) ( 3.14 * x * x )


main( )
{
float r1 = 6.25, r2 = 2.5, a ;
a = AREA ( r1 ) ;
printf ( "\nArea of circle = %f", a ) ;
a = AREA ( r2 ) ;
printf ( "\nArea of circle = %f", a ) ;
}

Here’s the output of the program...

Area of circle = 122.656250


Area of circle = 19.625000

After the above source code has passed through the preprocessor, what the compiler gets to
work on will be this:

main( )
{
float r1 = 6.25, r2 = 2.5, a ;

a = 3.14 * r1 *r1 ;
printf ( "Area of circle = %f\n", a ) ; a = 3.14 *r2
* r2 ;
printf ( "Area of circle = %f", a ) ;
}

Here is another example of macros with arguments:

Example 1:

#define ISDIGIT(y) ( y >= 48 && y <= 57 )


main( )
{
char ch ;
printf ( "Enter any digit " ) ;
scanf ( "%c", &ch ) ;

if ( ISDIGIT ( ch ) )
printf ( "\nYou entered a digit" ) ;
else
printf ( "\nIllegal input" ) ;
}

Example 2:
#define SQUARE(n) n * n
main( )
{
int j ;

j= 64 / SQUARE ( 4 ) ;
printf ( "j = %d", j ) ;
}

The output of the above program would be:


j= 64

#undef Directive
On some occasions it may be desirable to cause a defined name to become ‘undefined’. This
can be accomplished by means of the #undef directive. In order to undefine a macro that has
been earlier #defined, the directive,

#undef macro template

can be used. Thus the statement,

#undef PENTIUM

would cause the definition of PENTIUM to be removed from the


system. All subsequent #ifdef PENTIUM statements would
evaluate to false. In practice seldom are you required to undefine a macro, but for some reason if
you are required to, then you know that there is something to fall back upon.

Macros versus Functions


In a macro call the preprocessor replaces the macro template with its macro expansion, in
a stupid, unthinking, literal way. As against this, in a function call the control is passed to a
function along with certain arguments, some calculations are performed in the function and a
useful value is returned back from the function.

If we use a macro hundred times in a program, the macro expansion goes into our
source code at hundred different places, thus increasing the program size. On the other
hand, if a function
is used, then even if it is called from hundred different places in the program, it would take
the same amount of space in the program.

But passing arguments to a function and getting back the returned value does take time and
would therefore slow down the program.
This gets avoided with macros since they have already been expanded and placed in
the source code before compilation.

File Inclusion
The second preprocessor directive is file inclusion. This directive causes one file to be
included in another. The preprocessor command for file inclusion looks like this:

#include "filename"

and it simply causes the entire contents of filename to be inserted into the source code at
that point in the program. Of course this presumes that the file being included is existing. It
can be used in two cases:

(a) If we have a very large program, the code is best divided into several different files,
each containing a set of related functions. It is a good programming practice to keep
different sections of a large program separate. These files are

#include at the beginning of main program file.

(b) There are some functions and some macro definitions that we need almost in all
programs that we write. These commonly needed functions and macro definitions can be
stored in a file, and that file can be included in every program we write, which would add
all the statements in this file to our program as if we have typed them in.
It is common for the files that are to be included to have a ( .h ) extension. This extension
stands for ‘header file’, possibly because it contains statements which when included go to
the head of your program.

Actually there exist two ways to write #include statement. These


are:

#include "filename"
#include <filename>

The meaning of each of these forms is given below:

#include "goto.c"

This command would look for the file goto.c in the current directory as well as the
specified list of directories as mentioned in the include search path that might have been
setup.

#include <goto.c>

This command would look for the file goto.c in the specified list of directories (Search path)
only.

If you are using Turbo C/C++ compiler then the search path can be setup by selecting
‘Directories’ from the ‘Options’ menu. On doing this a dialog box appears. In this dialog
box against ‘Include Directories’ we can specify the search path. We can also specify
multiple include paths separated by ‘;’ (semicolon) as shown below:

c:\tc\lib ; c:\mylib ; d:\libfiles


The path can contain maximum of 127 characters. Both relative and absolute paths are
valid. For example ‘..\dir\incfiles’ is a valid path.

Program :

First create two programs

prog1.h (header file) prog2.c (source file)


#include<stdio.h> #include<stdio.h>
#include “prog1.h” // include header file prog1
void display()
{ void main()
printf(“\nThis is prog1 header file\n”); {
printf(“Welcome to display () function”); clrscr();
} display(); // call display() of prog1.h
void print(char *s) print(“My Name is SABAB”); // call print()
{ getch();
printf(“\n%s”,s); }
Execute
} prog2.c (ctrl + f9)

Output:

This is prog1 header file


Welcome to display () function
My Name is SABAB

Conditional Compilation
Conditional inclusions (#ifdef, #ifndef, #if, #endif, #else and #elif)

These directives allow to include or discard part of the code of a program if a certain condition
is met.

#ifdef allows a section of a program to be compiled only if the macro that is specified as the
parameter has been defined, no matter which its value is. For example:

#ifdef TABLE_SIZE
int table[TABLE_SIZE];
#endif

In this case, the line of code int table[TABLE_SIZE]; is only compiled if TABLE_SIZE was
previously defined with #define, independently of its value. If it was not defined, that line will not
be included in the program compilation.
#ifndef serves for the exact opposite: the code between #ifndef and #endif directives is only
compiled if the specified identifier has not been previously defined. For example:

#ifndef TABLE_SIZE
#define TABLE_SIZE 100
#endif
int table[TABLE_SIZE];

In this case, if when arriving at this piece of code, the TABLE_SIZE macro has not been
defined yet, it would be defined to a value of 100. If it already existed it would keep its previous
value since the #define directive would not be executed.

The #if, #else and #elif (i.e., "else if") directives serve to specify some condition to be met in
order for the portion of code they surround to be compiled. The condition that follows #if or #elif
can only evaluate constant expressions, including macro expressions. For example:

#if TABLE_SIZE>200
#undef TABLE_SIZE
#define TABLE_SIZE 200

#elif TABLE_SIZE<50
#undef TABLE_SIZE
#define TABLE_SIZE 50

#else
#undef TABLE_SIZE
#define TABLE_SIZE 100
#endif

int table[TABLE_SIZE];

Notice how the whole structure of #if, #elif and #else chained directives ends with #endif.

The behavior of #ifdef and #ifndef can also be achieved by using the special operators defined
and !defined respectively in any #if or #elif directive:

#if !defined TABLE_SIZE


#define TABLE_SIZE 100
#elif defined ARRAY_SIZE
#define TABLE_SIZE ARRAY_SIZE
int table[TABLE_SIZE];
#endif

Miscellaneous directives
Stringize (#):
The stringize or number-sign operator ('#'), when used within a macro definition, converts a
macro parameter into a string constant. This operator may be used only in a macro that has a
specified argument or parameter list.

When the stringize operator immediately precedes the name of one of the macro parameters,
the parameter passed to the macro is enclosed within quotation marks and is treated as a
string literal. For example:
#include <stdio.h>

#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")

int main(void)
{
message_for(Carole, Debra);
return 0;
}

This will produce following result using stringization macro message_for

Carole and Debra: We love you!

Token Pasting (##):


The token-pasting operator (##) within a macro definition combines two arguments. It permits
two separate tokens in the macro definition to be joined into a single token.

If the name of a macro parameter used in the macro definition is immediately preceded or
followed by the token-pasting operator, the macro parameter and the token-pasting operator
are replaced by the value of the passed parameter.Text that is adjacent to the token-pasting
operator that is not the name of a macro parameter is not affected. For example:

#define tokenpaster(n) printf ("token" #n " = %d", token##n)

tokenpaster(34);

This example results in the following actual output from the preprocessor:
printf ("token34 = %d", token34);

This example shows the concatenation of token##n into token34. Both the stringize and the
token-pasting operators are used in this example.

Line control (#line)


When we compile a program and some error happens during the compiling process, the
compiler shows an error message with references to the name of the file where the error
happened and a line number, so it is easier to find the code generating the error.

The #line directive allows us to control both things, the line numbers within the code files as
well as the file name that we want that appears when an error takes place. Its format is:

#line number "filename"

Where number is the new line number that will be assigned to the next code line. The line
numbers of successive lines will be increased one by one from this point on.

"filename" is an optional parameter that allows to redefine the file name that will be shown. For
example:

#line 20 "assigning variable"


int a?;
This code will generate an error that will be shown as error in file "assigning variable", line 20.

Error directive (#error)


This directive aborts the compilation process when it is found, generating a compilation the
error that can be specified as its parameter:

#ifndef __cplusplus
#error A C++ compiler is required!
#endif

This example aborts the compilation process if the macro name __cplusplus is not defined (this
macro name is defined by default in all C++ compilers).

Pragma directive (#pragma)

This directive is used to specify diverse options to the compiler. These options are specific for the
platform and the compiler you use. Consult the manual or the reference of your compiler for more
information on the possible parameters that you can define with #pragma.

If the compiler does not support a specific argument for #pragma, it is ignored - no error is
generated.

1- #pragma startup and #pragma exit: These directives allow us to specify


functions that are called upon program startup (before main( )) or program exit
(just before the program terminates). Their usage is as follows:

Example :

void fun1( ) ;

void fun2( ) ;

#pragma startup fun1


#pragma exit fun2

main( )
{
printf ( "\nInside maim" ) ;
}

void fun1( )
{
printf ( "\nInside fun1" ) ;
}

void fun2( )
{
printf ( "\nInside fun2" ) ;
}

And here is the output of the program.

Inside fun1
Inside main
Inside fun2

2- #pragma warn: This directive tells the compiler whether or not we want to
suppress a specific warning. Usage of this pragma is shown below.

#pragma warn -rvl /* return value */


#pragma warn -par /* parameter not used */
#pragma warn -rch /* unreachable code */

int f1( )
{
int a = 5 ;
}

void f2 ( int x )
{
printf ( "\nInside f2" ) ;
}

int f3( )
{
int x = 6 ;
return x ;
x++ ;
}

void main( )
{
f1( ) ;
f2 (7 ) ;
f3( ) ;
}
File Handling
What is a File?
Wherever there is a need to handle large volumes of data it is advantageous to store data
on the disks- and read whenever necessary. This method employs the concept of files to
store data. A file is place on the disk where a group of related data is stored. C supports a
number of functions that have the ability to perform basic file operations, which include:
 Naming a file

 Opening a file

 Reading data from\a file

 Writing data to a file

 Closing a file
There are two distinct ways to perform file operations in C.

 Low-level I/O Operation (It uses UNIX system calls)

 High-level I/O Operation (It uses functions in C's Standard I/O library)

The list of high level I/O functions is given below:

Function Name Operation


fopen() Creates a new file for use or opens an existing file for use.
fclose() Closes a file which has been opened for use.

fgetc() Reads a character from a file.

fputc() Writes a character to a file.

getc() Reads a character from a file (it is a macro)

putc() Writes a character to a file. ( it is a macro)

fprintf() Writes a set of data values to a file.

fscanf() Reads a set of data values from a file.


getw() Reads an integer from a file.

putw() Writes an integer to a file.

fgets() Read a line of text from a file.

fputs Write a line of text to a file.

fwrite() Write set of data to a file.

fread() Read set of data from a file.

Defining and Opening a File


Before storing data in a file in the secondary memory certain things about the file must be
specified to the operating system. They include:
 Filename
 Data Structure
 Purpose

Filename: is a string of characters that make up a valid filename for operating system. It
may contain two parts, a primary name, and an optional period with the extension.
Example: Input.dat
Data Structure of a file is defined as FILE in the library of standard I/O function definitions.
Purpose: when we open a file, we must specify what we want to do with the file.

To open a file, the function is fopen().


fopen() performs three important tasks:

 Firstly, it searches on the disk the file to be opened.


 Then it loads the file from the disk into the place in memory called buffer.
 It sets up a character pointer that point to the first character of the buffer.

Following is the general format for declaring and opening a file:


FILE *fp;
fp = fopen ( "filename", "mode");

The first statement declares the variable fp as a "pointer to the data type FILE".
The second statement opens the file named filename and assigns an identifier to the FILE type
pointer fp. This pointer which contains all the information about the file.
The second statement also specifies the purpose of opening this file. The mode does this job .
The Mode can be one of the following:
Both the filename and mode are specified as string. They should be enclosed in double
quotation
marks.
e.g
“w”
“r”
”a”
The additional modes of operation are:
r+ The existing file is opened from the beginning for both reading and writing.
w+ Same as w except both for reading and writing.
a + Same as a except both for reading and writing.

Whenever a file is opened using fopen() function, a file pointer is returned. If the file
cannot be opened for some reason, then the function returns a null pointer.

Example:
if (fp = = NULL)
printf ("File could not be opened.\n");

Closing a File
Once all the operations on a file have been completed, the file is closed. This is done to clear
the buffers and flush all the information associated with the file. It also prevents any accidental
misuse of the file.
When there is a need to use a file in a different mode, the file has to be first closed and then
reopened in a different mode.
The I/O library supports a function for this of the following form.
fclose (file_pointer);
This would close the file associated with the FILE pointer filepointer.

Example:
FILE *p1, *p2;
p1 = fopen ("INPUT", "w');
p2 = fopen ("OUTPUT", "r");
----------------
---------------
---------------
fclose(p1);
fclose(p2);
Input / Output Operations on Files

getc and putc Function


putc can be used to write a character in a file opened in write mode . A statement like
putc (ch, fp1);

writes the character contained in the character variable ch to the file associated with
file pointer fp1.

Similarly, getc is used to read a character from a file that has been opened in read mode.
The statement c = getc(fp2);
would read a character from the file whose file pointer is fp2.

The file pointer moves by one character position for every operation of getc or
putc.
The getc will return an end-of-file marker EOF, when end of the file has been reached.
The
reading should be terminated when EOF is encountered. Testing for the end-of-file
condition
is important.

Example: /* A program for read characters from keyboard and writes into a file. */

#include<stdio.h>
#include<conio.h>
void main()
{
FILE *fp;
char ch;
clrscr();
fp=fopen(“C:\\temp\\mydata.txt”,”w+”); // opens a file mydata.txt in write and read
mode.
if(fp==NULL)
{
printf(“ File Not Created ! or Opened !”);
getch();
exit(0);
}
printf(“Enter Your Contents:”);
ch=getchar();
while(ch ! = -1) // read while inputted character in not -1 (Ctrl +z)
{
putc(ch,fp); // write a character stored in ch into file pointed by fp
ch=getchar(); // Read character from keyboard
}

rewind(fp) ; // skip filepointer at beginning of file.


printf(“\nYour Contents are:\n”);
ch=getc(fp);
while(ch ! = EOF) // read while character in not EOF
{
printf(“%c”,ch); // write a character stored in ch on console
ch=getc(fp);
}
fclose(fp); // closing file.
getch();
}

getw() and putw() Functions


The getw and putw are integer-oriented functions. They are similar to the getc and putc
functions and are used to read and write integer values.
The general forms of getw and putw are:
putw (integer, fp); & getw (fp);

Example : /* Program to Write/Read numbers stored in an Array into a file */

#include<stdio.h>
void main()
{
int arr2[5]={2,3,4,6,7}, arr2[5] ,i;
FILE *fp;
clrscr();
fp=fopen(“C:\\temp\\mydata.txt”,”w+”); // opens a file mydata.txt in write and read
mode.
if(fp==NULL)
{
printf(“ File Not Created ! or Opened !”);
getch();
exit(0);
}
for(i=0;i<5;i++)
{
putw(arr1[i],fp); // write Array elements into file
}
rewind(fp); // Jump file pointer at beginning of file
for(i=0;i<5;i++)
{
arr2[i]=getw(fp); // Read Numbers and store in second array named arr2
}
printf(“Your Elements of Second Array are:”);
for(i=0;i<5;i++)
{
printf(“\t%d”,arr2[i]);
}
getch();
}
fprintf() and fscanf() Functions
The functions fprintf and fscanf perform I/O operations that are identical to the familiar
printf and scanf functions.

The general syntax of fprintf is


fprintf (fp, "control string", list);

where “fp” is a file pointer associated with a file that has been opened for writing. The
control string contains output specifications for items in the list. The list may include variables,
constants and strings.

Example: fprintf (f1,"%s %d %f', name, age, 7.5);


here name is an array variable of type char and age is an int variable.

The general syntax of fscanf is


fscanf (fp, "control string", list);

This statement would cause the reading of the items in the list from the file specified
by fp, according to the specifications contained in the control string.

Example: fscanf (f2, "%s %d", item,


quantity);

fscanf also returns the number of items that are successfully read. When the end of
file is reached, it returns the value EOF.
Program:
#include<stdio.h>
#include<conio.h>
void main()
{
int roll;
char *name;
FILE *fp;
clrscr();
fp=fopen(“c:\\temp\\student.txt”,”w+”);
fprintf(fp,“%d\n %s”,101,”Rahul”); // writes “101” and “Rahul” to file
rewind(fp);
fscanf(fp,“%d %s”,&roll,name); // read data from file and store in variables roll and
name
printf(“Your Data is :\n”);
printf(“Roll Number : %d\n”,roll);
printf(“Name : %s\n”,name);
getch();
}

Output

feof() Function
The feof function can be used to test for an end of file condition. It takes a FILE pointer as
 its only argument and returns a non zero integer value if all of the data from the specified
file has been read, and returns zero otherwise. If fp is a pointer to the file that has just
been
opened for reading, then the statement.

if (feof (fp))
printf ("End of data.\n");
would display the message "End of data." on reaching the end of file condition.

Functions for Random Access to Files


To randomly access only a particular part of a file, the following functions are provided in
C.

 ftell
 rewind

 fseek

ftell() Function
ftell takes a file pointer and returns a number of type long that corresponds to the
current position.

This function is useful in saving the current position of a file, which can be used later in
the program.
It is used as follows:

n = ftell (fp):

n would give the relative offset (in bytes) of the current position. This means that n
bytes have already been read (or written).

rewind( ) Function
rewind takes a file pointer and resets the position to the start of the file .

For example, the statements


rewind (fp);
n= ftell (fp);

would assign 0 to n because the file position has been set to the start of the file by
rewind.

fseek( ) Function
fseek function is used to move the file position to a desired location within the file.

Its syntax is

fseek (fileptr, offset, position);

 fileptr is a pointer to the file concerned.


 offset is a number or variable of type long. It specifies the number of positions
(bytes) to be moved from the location specified by position
 position is an integer number. It can take one of the following three values:

Value Meaning
0 Beginning of file
1 Current Position
2 End of file

The offset may be positive to move forwards, or negative to move backwards.


The following examples give you an idea about the operation of the fseek function:

Statement Meaning
fseek (fp, 0L, 0); Go to the beginning (Similar to rewind)
fseek (fp, 0L, 1); Stay at the current position. (Rarely used)
fseek (fp, 0L, 2); Go to the end of the file, past the last- character of the file.
fseek (fp, x, 0); Move to (x+ 1) th byte in the file.
fseek (fp, x, 1); Go forward by x bytes from current position
fseek (fp, -x, 1); Go backwards by x bytes from the current position.
fseek (fp, -x, 2); Go backwards by x bytes from the end-of-file position.

Program:

#include <stdio.h>
void main()
{
FILE * f;
char *str;
f = fopen("myfile.txt", "w");
fputs("Hello World", f); // write Hello World into file
fseek(f, 6, SEEK_SET);
fputs(" India", f); //override World with India
rewind(f);
fgets(str,20,f);
printf(“\nData of file : %s “,str);
fclose(f);
getch( );
}

Output : Hello India


Unformatted data files
Some applications 'need to access records or blocks of data. This can be implemented
through the case of fread and fwrite functions.
These functions are often referred to as unformatted read and write functions.

Syntax :
fread (&buf, sizeof (buffer), number of records, file pointer) ;
fwrite (&buf, sizeof (buffer), number of records, file pointer);

/* example to use fread() and fwrite() */

Example 1:

#include<stdio.h>
void main()
{
FILE *fp = NULL;

short x[10] = {1,2,3,4,5,6,5000,6,-10,11};


short result[10];

fp=fopen("c:\\temp\\data.bin", "wb+");

if(fp != NULL)
{
fwrite(x, 2 /*sizeof(short)*/, 10 /*20/2*/, fp);
rewind(fp);
fread(result, 2 /*sizeof(short)*/, 10 /*20/2*/, fp);
}
else
exit(0);

printf("\nResult");
for(i=0;i<10;i++)
{
printf("\n%d",result[i]);
}
fclose(fp);
getch();
}
Example 2: /* program for read and write records from/to file */

typedef struct xyz


{
int roll;
char name[20];
}student;

void main()
{
student st1,st2;
FILE *fp;
clrscr();
fp=fopen(“C:\\temp\\rec.txt”,”w+”);
if(fp !=NULL)
{
printf(“Enter Roll Number and Name :”);
scanf(“%d %s”,&st1.roll,st1.name); // read record in variable st1 from
keyboard
fwrite(&st1,sizeof(st1),1,fp); // write struct st1 to file
rewind(fp);
fread(&st2,sizeof(st2),1,fp); // Read record from file and store in struct st2
printf(“\nThe Records are :\n”);
printf(“\nRoll Number : %d”,st2.roll);
printf(“\nStudent Name : %s”,st2.name);
}
getch();
}

Output:

You might also like