Pages

Friday, December 31, 2010

Adding nodes anywhere in a single linked list

In the previous code, the only way to add a new node to the linked list was to add it at the end of the list, but if required a node can be added to the beginning or the middle of the list. To add a node any where in the list, just replace the add() function given in the previous post with the code given below. The code will ask the user to specify where the new node is to be added - at the end, middle or the beginning.

 void add()
{
    clrscr();
    int c,id;
    person *pers,*ptr,*prev;
    pers=(person *) malloc(sizeof(person));
    if(pers==NULL)
    {
        printf("\nNot enough memory");
        return;
    }
    printf("\nEnter Person Id ");
    scanf("%d",&pers->personid);
    printf("\nEnter Person name ");
    scanf("%s",&pers->name);
    if(start==NULL) // checking if this is the first node
    {
        start=pers; // to make it the first node, make start point to it
        pers->next=NULL;// since it is the first node, its next part will store NULL
    }
    else // from 2nd node onwards
    {
        printf("\n1. Add Person to the end ");
        printf("\n2. Add Person to the beginning");
        printf("\n3. Add Person to the middle");
        printf("\nEnter your choice ");
        scanf("%d",&c);
        if(c==1)
        {
            for(ptr=start;(ptr);ptr=ptr->next) // searching for the last node of the list
                prev=ptr;
            prev->next=pers; // making next of last node point to the new node
            pers->next=NULL; // new node's next is NULL
            printf("\nNode added at the end");
        }
        else if(c==2) // adding a node at the beginning
        {
            pers->next=start;// the new node will point to the current start node
            start=pers; // start will point to the new node.
            printf("\nNode added at the beginning");
        }
        else
        {
            printf("\nEnter Person Id Before which the new node is to be added ");
            scanf("%d",&id);
            for(ptr=start;(ptr);ptr=ptr->next)
            {
                if(ptr->personid==id)
                {
                     pers->=prev->next;
                     prev->next=pers;

                }
                prev=ptr;
            }
        }
    }
    printf("\nPerson Added. Press enter to continue...");
    getch();
    clrscr();
}

Thursday, December 30, 2010

Single Linked List : Source Code

#include

#include

#include // for malloc() and free()


struct person
{
int personid;
char name[15];

person *next;
}*start;// start points to the first node

void main()
{
start=NULL;// till there is node keep start as null
void add();
void traverse(); // to display all nodes
void search();
void del();
int c;
do
{
printf("\nMAIN MENU");
printf("\n1. Add a person");
printf("\n2. Display all persons");
printf("\n3. Search a person");
printf("\n4. Delete a person");
printf("\n5. Quit");
printf("\nSelect your choice ");
scanf("%d",&c);
if(c==1)
add();
else if (c==2)
traverse();
else if(c==3)
search();
else if(c==4)
del();
}while(c!=5);
}
void add()
{
clrscr();
person *pers,*ptr,*prev;
pers=(person *) malloc(sizeof(person)); // allocating memory using the malloc()
if(pers==NULL)// in case allocation is unsuccessful
{
printf("\nNot enough memory");
return;
}
// if allocation succeeds
printf("\nEnter Person Id ");
scanf("%d",&pers->personid);
printf("\nEnter Person name ");
scanf("%s",&pers->name);
if(start==NULL) // checking if this is the first node
{
start=pers; // to make it the first node, make start point to it
pers->next=NULL;// since it is the first node, its next part will store NULL
}
else // from 2nd node onwards
{
for(ptr=start;(ptr);ptr=ptr->next) // searching for the last node of the list
      prev=ptr;
prev->next=pers; // making next of last node point to the new node
pers->next=NULL; // new node's next is NULL
}
printf("\nPerson Added. Press enter to continue...");
getch();
clrscr();
}

void traverse() // printing the linked list
{
clrscr();
person *ptr;
if(start==NULL) // checking if nodes have been added or not
{
printf("\nNo Person Found");
return;
}
for(ptr=start;(ptr);ptr=ptr->next)// looping from the start till the end of the list
{
printf("\nPerson Id : %d",ptr->personid);//printing the details
printf("\nName : %s",ptr->name);
printf("\n---------------------------");
}
printf("\nEnd of list");
printf("\nPress enter to continue..");
getch();
clrscr();
}
void search()
{
clrscr();
printf("\nSearch a person");
int pid,flag;
char ch;
person *ptr;
if(start==NULL)
{
printf("\nNo Person Found");
return;
}
printf("\nEnter Person Id To Search : ");
scanf("%d",&pid);
for(ptr=start;(ptr);ptr=ptr->next)
{
if(ptr->personid==pid)
{
flag=1;
printf("\nPerson Found");
printf("\n=============");
printf("\nPerson Id : %d",ptr->personid);
printf("\nName : %s",ptr->name);
fflush(stdin);
printf("\nDo you want to modify the data? : ");
scanf("%c",&ch);
if(ch=='y' || ch=='Y')
{
printf("\nEnter New Person Id "); // overwriting the data
scanf("%d",&ptr->personid);
printf("\nEnter New Name ");
scanf("%s",&ptr->name);
printf("\nData Updated !!");
}
}
}


if(flag!=1)
printf("\nPerson Id %d not found",pid);
}


void del()
{
clrscr();
printf("\nDelete a person");
person *ptr,*prev;
int pid,flag;
char ch;
if(start==NULL)
{
printf("\nNo Person Found");
return;
}
printf("\nEnter Person Id To Delete : ");
scanf("%d",&pid);
for(ptr=start;(ptr);ptr=ptr->next)
{
if(ptr->personid==pid)
{
flag=1;
printf("\nPerson Found");
printf("\n=============");
printf("\nPerson Id : %d",ptr->personid);
printf("\nName : %s",ptr->name);
fflush(stdin);
printf("\nDo you want to delete the data? : ");
scanf("%c",&ch);
if(ch=='y' || ch=='Y')
{
if(ptr->next==NULL) // if the last node is to be deleted
prev->next=NULL;
else if(ptr==start) // if the first node is to be deleted
start=ptr->next;
else
prev->next=ptr->next;// deleting the middle node
free (ptr); // freeing memory using the free()
printf("\nPerson Deleted");
}
}
prev=ptr;
}
if(flag!=1)
printf("\nPerson Id %d not found",pid);
}


Data Structure - Linked List

Dynamic memory management is best understood using the concepts of data structure. Data structures use dynamic memory management to allocate and deallocate memory during the run time.

Linked List  : Linked list can be defined as a logical chain of memory blocks (called nodes)where each block contains data as well as the address of the next logical node in the collection. To understand it better, let's compare a linked list with an array. An array is a collection of values of similar types. When we declare an array, we are only concerned about the data that we want to store in the array, not the memory. Memory to an array is assigned automatically by the compiler in contiguous form. Contrary to this the "elements" of a linked list not only store the data as arrays do, they also store the address of the next node in the chain.

Why do nodes store the address?
You may be wondering about what is the need to store the address of any node. This is what data structures are all about. Since memory to a data structure, like linked list is allocated dynamically during the runtime, it is not known beforehand what will be the address of the next created node. It is just the opposite of array where each element is addressed relative to the previous element. When the address of a node is not known, how will we access its data? That's why we keep track of the address of the nodes as well.

Basic operations on a linked List
A link list allows the following operations on it.
  1. Insertion : A new node can be added to a list at the beginning, middle or at the end.
  2. Traversal : Traversal is the process in which we can read the nodes of the linked list one by one.A double link list can be traversed both ways, from beginning to end and to end to beginning.
  3. Deletion : Being a data structure, linked list allows the user to delete unused nodes from the collection.
  4. Searching : A linked list can be searched for a particular information as well. This is done by reading the list from "start" till the end.

Types of linked list
1. Single Linked List
2. Double Linked List
3. Circular Linked List

Single Linked List : A single linked list is a linked list where each node stores the address of the next node. A special pointer which is usually called "start" or "head" points to the first node of the collection.
This is how a single linked list looks like.

Single Linked List
As you can see each node is divided into two parts, data and address. Data contains any type of data that we want to store like "no,name, teleno" etc. The address part contains the address of the next node. The last node of a single linked list contains "NULL", since there is no node to which it can point. To access a linked list, all we have to do is to find the node to which "head" is pointing to, from thereon all nodes are connected so we can easily move from one node to another. The compiler assumes that there is always a possibility that new nodes will be inserted in the list, therefore there should be some methodology to allocate unused memory for the new nodes. Also, there must be some technique to release memory of the deleted nodes. This technique is incorporated by C, using a special list which contains the information about unused memory cells. This list has its own pointers pointing to the next free node and is called "Free-Pool". When a new node is added the number of free nodes is reduced and with every deletion the number increases.

Application of Linked List
  1. The main Applications of Linked Lists are
  2. For representing Polynomials
  3. It means in addition/subtraction /multiplication of two polynomials.
  4. Eg:p1=2x^2+3x+7 and p2=3x^3+5x+2
  5. p1+p2=3x^3+2x^2+8x+9
  6. In Dynamic Memory Management
  7. In allocation and releasing memory at runtime.
  8. In Symbol Tables
  9. In Balancing parentheses
  10. Representing Sparse Matrix

Tuesday, December 28, 2010

Dynamic memory allocation

The process of allocating memory at run time is known as "Dynamic memory allocation". C uses some memory management functions, which can be used to allocate and deallocate memory during the program execution. This a very useful method for handling memory related tasks since the memory is allocated "on demand". It is very different from static allocation where the memory is allocated at the time of compilation. This method is mainly used when number of data items can change during the execution of a program. For example,the number of goods a customer has bought can increase or decrease during the shopping at any time. When the list grows we need to provide it more space to accommodate additional data items. Such situations can be handled move easily by using dynamic techniques. Dynamic allocation optimizes the storage space. The following functions are used in c for purpose of memory management.


Dynamic Memory Management Functions
  1. malloc : Allocates memory requests size of bytes and returns a pointer to the 1st byte of allocated space.
  2. calloc : Allocates space for an array of elements initializes them to zero and returns a  pointer to the memory.
  3.  free : Frees previously allocated space
  4.  realloc : Modifies the size of previously allocated space.

Memory allocations process:
All the program instructions and global and static variables are stored in a permanent storage area whereas local variables are stored in stacks. The memory space that is located between these two regions in available for dynamic allocation during the execution of the program. As told earlier, this free memory region is called the "heap memory" or the "free store". The size of heap keeps changing when program is executed due to creation and termination of variables that are local for a particular function and blocks (for example a variable declared inside a for loop). Therefore it is possible to encounter memory overflow during dynamic allocation process. In such situations, the memory allocation functions mentioned above will return a null pointer. Allocating a block of memory:

malloc
To allocate a block of memory we can use the "malloc" function which is found in the header file "malloc.h". The malloc function creates a block of memory of specified size and returns a pointer pointing to the first byte of the allocated memory. For example, if the address of the first allocated byte is 1001, the malloc function will return 1001. We must cast(convert) this address before using it as evident from the syntax given below.

Syntax:

ptr=(cast-type*)malloc(size);
where ptr is a pointer of type casttype. The malloc() returns a pointer (of cast type) to an area of memory with size size.

Example:
ptr=(float *) malloc(sizeof(float));

The above code will allocate a memory that is sufficient to store a float value (4 bytes in most cases) and returns the address of the first byte of memory allocated is assigned to the pointer ptr.

To allocate more memory you can use the following statement

ptr=(float *) malloc(10*sizeof(float));
This statement will allocate 40 bytes of memory since we have asked it to allocate 10*4 bytes.

calloc()

Allocating multiple blocks of memory: The function "calloc()"  is  used to request multiple blocks of storage each of the same size and then sets all bytes to zero.

Its syntax is :

ptr=(casttype*) calloc(n,size);


As you can see the syntax is almost similar to "malloc()" but the difference is that when "calloc()" is used it   allocates contiguous space for n blocks each size of "size" bytes and intialises each byte with a "0" (Zero).

free()
Releasing the used space: Dynamic allocation is of no use if we can not deallocate or delete the memory which is of no longer required. Deleting such memory blocks will keep the "heap" ever ready with memory to handle any future demands. To delete such memory the function "free()" is used. This function should be passed with the address of the memory that we want to delete.
Syntax :
free(ptr);

where ptr is a pointer that was created using malloc() or calloc(). For example, to deallocate the memory which was allocated using the "malloc()" function above, we will write:

free(ptr)

This statement will release 4 bytes of memory which can be used for any future allocation.

realloc()
To modify the size of any existing allocated memory:  There can be some conditions where you find that the memory which was  allocated by  malloc or calloc is insufficient or in excess. In this case we can change the memory size using the function "realloc". This process is called reallocation of memory.
Syntax:
ptr=realloc(ptr,newsize);

This function allocates new memory space of size newsize to the pointer variable ptr and returns a pointer to the first byte of the memory block. The allocated new block may be or may not be at the same region.

Thursday, December 23, 2010

Memory Management - Static Memory Management

In C or C++, you can assign memory to a variable or an object in two ways,
1. Static Allocation
2. Dynamic Allocation

which method will be used to allocate memory, depends on whether the data is fixed or varying. If the amount of data is fixed the static allocation method should be used and in case of varying data, the dynamic allocation method is more suitable.


Static Memory Allocation
As you know a single variable can hold only a single value, whereas an array can store multiple values. For example, if you wish to store salary of an employee, you can simply create a variable and store the salary there. However, if the number of employees is quite large, say 50 or 100, you can create an array of the same size and store the data. The array will save you from the trouble of declaring so many variables. But  whatif the number of employees is not known? Even an array will not help you . Why, because the arrays are static in nature. Once you declare an array, you can not be modify while the program is running or what is known as the "run time". So if you are asked to store the salaries of "some" employee how large an array would you create? If you say 50, and the actual number of employees is just 5 then? In this case the remaining memory will be wasted. If a smaller size is decided upon, it will lead to loss of data. To sum it up, following are the disadvantages of an
array.
1. You can not insert an element in an array during the run time.
2. You can not delete an element from an array during the run time.

Therefore arrays are recommended only when amount of memory is known beforehand, otherwise you will either lose memory or data.
The core of the problem is the way the memory is being allocated - Statically. The moment you write a statement like "int a", 2 bytes of memory are set aside for the variable "a". This memory will be allotted to the variable whether or not you initialize the variable. This poses a serious problem - suppose you have a float array of 100 elements(100 x 4 = 400 bytes), which is not needed after the first 10 lines of the program. From 11th line onwards will the array still occupy 400 bytes or not? The answer is Yes.t The memory which is assigned to a variable statically cannot be deallocated even if the user wishes. Therefore if you keep allocating memory to variables, chances are you may run out of memory.

Is wastage of memory such an issue?
Some people would say, "I need not worry about memory, I have 4 GB RAM in my system. So even if 1 or 2 MB goes waste, it is not a big problem". They are wrong, it is a big problem for the reasons given below.
1. You are not making the program for yourself. The program is made for the user or the client. You may be having 3 to 4 GB of RAM in your system, but what if the user is still using a decade old system which  has 64 or 128 MB RAM. It will be a costly affair for such a user if some memory is wasted by the program. Asking the user to upgrade the same is not always recommended.

2. For those who have sufficient amount of RAM, they need to keep in mind that even they can't afford to waste it. Here's why - Let's take an example of a system which has 1 GB of RAM. The moment the system is switched on, a small part of this memory is spent in displaying graphics on the monitor which is called the shared memory. When the initial process completes, the OS (Windows, Linux or any other)  starts to load into the memory which is called "booting". OS consumes a lot of memory to load, specially the new ones like Windows Vista or Windows 7. Once the system is up and running the user starts opening applications which he wants to use, like a media player,word,excel or any other program. Each program or the file the user opens gets loaded in RAM, thereby decreasing it. When the user starts to write a program the compiler will not the count the memory as 1 GB. The amount of memory will be calculated in term of "free memory". which means the amount of physical RAM(1 GB) minus the amount of memory used by the OS and all the other programs. All of the free memory will not be given to the user to declare variables since the system will  need some memory for its internal processes also. Therefore it allots the program a very small amount of the available RAM called the free store or the
heap memory fulfil its needs. The size of the free store is relative to the amount of physical RAM, higher the RAM, more the free store. In a nutshell, the total RAM in your computer is not given to your program to process, just a small amount. To understand it, suppose the free store is of 1 MB and the program has 100 integer variables, 50 floats and 200 char variables, the program will demand a total of(100*2,50*4,200*1) 600 bytes from 1 MB. Don't forget that even a small "Student Management Program" will be needing more than 1 MB of RAM to declare the variables.
Dynamic Allocation is the answer to all the problems. If the memory is allocated dynamically it can be deallocated any time keeping the free store always ready with bytes of memory for future use.

Monday, December 20, 2010

Macros - #pragma Directive

The pragma Directive allows various instructions to be given to the compiler. Pragmas vary from a compiler to another. If we talk about Turbo C, it has some pragmas that can be used during the program creation.

1. #pragma startup
This directive is used to inform the compiler about the code that we want to run even before "main()".

Example

void welcome()
#pragma startup welcome
#include
void main()
{
    printf("I am the second one to be called");
}

void welcome()
{
    printf("I am running before main()");
}

The above program will print the message inside the welcome() before going to main. Till now we have read and practiced that main() is the first code to run, but as you can see we can write some code that will run before main() also.

2. #pragma exit : Opposite to #pragma startup, #pragma exit will run just before the termination of the program. It can be used to run the code that we want to be the last activity in a program. Let's rewrite the above code to understand its working


void welcome()
void goodbye()
#pragma startup welcome
#pragma exit goodbye
#include
void main()
{
    printf("I am the second one to be called");
}

void welcome()
{
    printf("I am running before main()");
}
void goodbye()
{
    printf("I am the last one");
}

The program will print the messages in the following order
welcome-->main-->goodbye

Macros - Conditional Compilation

Another use of macros is to use them for conditional compilation. By "conditional compilation", we mean that if certain portions of a program are to compiled only if a particular condition is met we can use these macros. Conditional compilation can be done using "ifdef" and "ifndef" macros,which mean ''if defined" and "if not defined," respectively. The working of #ifdef - #else - #endif is similar to the ordinary if - else statements.
The general form of #ifdef is
#ifdef macroname
statements
#endif

If macro-name has been previously defined in a #define statement, the block of code will be compiled.

Syntax
#ifndef macroname
statements
#endif



If macro-name is currently undefined by a #define statement, the block of code is compiled. Both #ifdef and #ifndef may use an #else or #elif statement.

For example

#include
#define DATA 100
void main()
{
#ifdef DATA
printf("DEFINED");
#else
printf("NOT DEFINED");
#endif
#ifndef VALUE
printf("VALUE is not defined\n");
#endif
}

The above program will print "DEFINED", since the macro DATA is defined. The message "VALUE is not defined" will also get printed since there is no macro defined by the name VALUE.

Such a technique is mainly used by the programmers to make their program work over different platforms. Using the "ifdef" macro we can write different codes for different type of platforms. For example, to process different type of codes for different type of OS we can write a code as
{
#ifdef WINDOWS7
write statement for Windows 7
#else
write statement for  Windows XP
#endif
}


The above code will check if a macro named WINDOWS7 is defined, if yes, it will process the statements written for Windows 7 otherwise will move to the next statement.

#if and #elif Directives
In addition to #ifdef, there is a another method to check whether a macro name is defined. We can
use the #if directive  with the defined compile-time operator.
Syntax
defined macroname

If macro name is defined, the expression will result in true, otherwise false.

Example
#if defined DATA
or
#ifdef DATA


The above 2 statements will check if the macro named "DATA" is defined or not.


#undef
The #undef directive undefines a previously defined macro definition.

Syntax
#undef macroname

For example:
#define HOUR 24
printf("\nThere are %d hours in a day",HOUR);
#undef HOUR

The above code first defines a macro named HOUR with a value of 24. The value is printed and then undefined using the #undef directive. After a macro is undefined you can not use it in the program. Although it is rarely used, we should have the knowledge about how to "undefine" a macro also.

Sunday, December 19, 2010

Macros - File Inclusion

The most common use of a macro is in including "external" files in our program. We use this kind of macro in almost every program when we include a header file. This directive simply "adds" an existing file to another file. The "include file" directive offers the following benefits.

1. If there are certain functions that we use quite frequently, for example in almost every program, creating them again and again would not make sense. What we can do is, store all such functions in a file and "include" them in every program they are required. You can say that this is like creating your own header file. Try it, put some commonly used functions in a new file, like adding 2 numbers, calculating square etc. Save this file in the "include" folder of your C installation,with any name of your choice(don't put spaces in between), but type the extension as ".h",for example "sample.h". Create another simple program file, and include the header file you just created using the include directive. Of course, the program will have the standard header files(stdio,conio) included also. Inside main(), try to call a function that you declared in "sample.h". You will see that the program will call the function from your header file, just like it does for predefined header files.

Example
// SAMPLE.H (SAVE IT IN THE "INCLUDE" FOLDER)
#include
int square(int n)
{
    return n*n;
}

// INCLUDING THE HEADER FILE
#include // pre defined header file
#include // user defined header file
void main()
{
    int num=5,r;
    r=square(num); // calling the function of sample.h
    printf("\nSquare is %d",r);
}


2. This technique can also make a large program small. If you have a large program which you are finding difficult to manage, you can break it into small manageable units. These units can then be "included" in the main program from where they will be called. In other words, if there is file handling program in which we have created separate functions to add,search,view, delete the records, we can save all the functions in a different files and call them from a main file.

For example
#include
#include
#include



How to use the "include" directive.

There are two methods of using the include directive:
  • Option 1 - #include
This statement will include the file "stdio.h" in the current file. This statement in fact is loading the "stdio.h" file in RAM so that the function given in it can be accessed.This command will search for the file stdio.h in the specified list of directories only. This "list of directories" is specified in different compilers differently. If you are using "Turbo C", you can specify the path by selecting "Options-> Directories" menu. When you will select "Directories" menu item, a dialog box titled "Directories" will be displayed. The first box in this dialog box will let you specify the directories in which a function is to be searched. The default path written here will be "c:\tc\include". This means that when you write "#include" in a program, the file is included from the "c:\tc\include" folder. If you want to specify more than 1 directory, you can write something like "c:\tc\include;c:\tc\myheader;c:\tc\headers;"
We can also specify multiple include paths separated by ‘;’ (semicolon) as shown above. Now any file that you include in the program will be first searched in "c:\tc\include", if found the file will be added, if not the same will be searched in the second directory "c:\tc\myheader", and the process will continue till the file is found. If the specified file is not found in any of the directories an error will be shown.
  • Option 2 - #include "stdio.h"
This command would look for the file "stdio.h" in the current directory as well as the specified list of directories as mentioned in the include search path that might have been set up.

Friday, December 17, 2010

Difference between a macro and a function

In all the examples given in earlier posts, you have seen that a macro is working somewhat like a function. Function, as you already know is used when we want to perform the same task again and again. Similarly,wherever we need to perform the same task, we can write the name of the macro like we do in a function. So when should we use a function and when a macro?

Which is better ?
1.    When we define a macro in our program and use it many times,the macro is expanded that many times resulting in an increase in the program size. Contrary to this, if a function is called numerous number of times, it would take the same amount of space in the program.
2. When we have a function with arguments, passing values to it and getting the returned value, takes some time. This time is saved in macros since they have already been expanded and placed in the source code before compilation.
3. When the task to be performed is small and easy, we should use macros as it will make use of the memory resources quite well, but if the task is heavy and you need to perform it frequently we should make space  for a function instead of a macro.
4. Macros make the program process fast, but the drawback is that they make the program large. Function, make the program smaller in size.

Thursday, December 16, 2010

Macros with Arguments

Like functions, macros too can have arguments. If a macro has been defined with arguments, the same should be passed while using it.

Example 1 : A macro to find out square of a number

#define SQUARE(no) (no * no )
void main( )
{
int num=4,sq;
sq = SQUARE (num) ;
printf ( "\nArea of circle = %d",sq) ;
}


In the above program, when the statement "SQUARE(no)" is encountered by the preprocessor it expands it to (no * no).  The "no" in the macro template is an argument that matches the no in the macro expansion ( no * no ). When the statement "SQUARE(no)" is written it copies the value of "num" to "no". Therefore the statment "SQUARE(num)" translates to "(num*num)". When the preprocessor has done its bit, the code is passed on to the compiler. The above program will be compiled like this

#define SQUARE(no) (no * no )
void main( )
{
int num=4,sq;
sq = num*num ;
printf ( "\nArea of circle = %d",sq) ;
}


Example 2 : To check if the given number is positive or negative


#include
#define CHECKPOS(n) (n>0)

void main()
{
    int value;
    printf("\nEnter a number : ");
    scanf("%d",&value);
    if(CHECKPOS(value))
        printf("\nPOSITIVE");
    else
        printf("\nNEGATIVE");
}



Example 3 : To check if the given number is an even or odd number.

#include
#define ISEVEN(num) (num%2==0)
void main()
{
    int no=1;
    if(ISEVEN(no))
        printf("\nEVEN");
    else
        printf("\nODD");
    }
}


Points to remember

1. Make sure that the macro expansion(body) is enclosed within a pair of circular brackets. For example, in the example 1 above don't write

#define SQUARE(no)  no * no // incorrect
 
Instead write

#define SQUARE(no) (no * no ) // correct
2. We can break a macro into two or more lines using a backslash at the end of the line.For example, the example 3 can be written as
#define ISEVEN(num)\
(num%2==0)

3.  Don't put a space between the macro and its value. For instance in the example 1 above don't put a space between SQUARE(macro name) and no (macro value)
// incorrect because of a space after SQUARE
#define SQUARE (no) (no * no )
// correct, no spaces.
#define SQUARE(no) (no * no)

Preprocessor

What is a Preprocessor
The preprocessor is a program that processes the source code of the program before it is sent to the compiler for compilation. They are mostly used when we include a header file in a program using a statement like #include but they can also be used to define macros.Before learning how to use preprocessor, let's first learn how a program executes.

Excecution of a program
When we write a program in C and compile it to see the output there are many phases in its life. The program travels through many stages before we see the output on the screen.For example, Suppose you have a program called "sample.c" and you compile it, the following actions will take place in the system to run it.
  • The source code is stored in "sample.c", so the expanded source code will be stored in a file havingthe same name as the source code file with the extension ".I". Therefore the expanded source code of "sample.c" will store as "sample.i"
  • Now when we compile this expanded source code another file is created with the extension ".obj" which stands for "object".
  • When this object code is linked with the object code of library functions the resultant executable code gets stored in "sample.exe"

    The Preprocessor
    The preprocessor offers several features called preprocessor directives. All these preprocessor directives start with a # symbol.In addition, each preprocessing directive must be on its own line. These directives are generally place in the beginning of the program, but can be put anywhere in the program.
    Let's learn the following preprocessor directive

    a) Macro expansion
    b) File inclusion
    c)Conditional Compilation
    d) Miscellaneous directives


    MACRO EXPANSION
    Syntax
    #define name value

    Where name is the name of the macro and value is the value that we want to assign to it.whenever name appears in the file, it will be replaced by the value.The name of the macros are also called "Macro Templates" while the values assigned to them is called "Macro Expression".

    Look at the statement given below
        #DEFINE DAYS 7
       
    The above statement is defining a macro named "DAYS" and assigning the value 7 to it. During preprocessing, the preprocessor will replace every occurrence of the word DAYS in the program body with 7.

    Take a look

    #define DAYS 7
    void main( )
    {
    printf ( "\n%d",DAYS) ;
    }

    When the above program is run, you will 7 printed on the screen as this was the value of the macro "DAYS".

    This is another example of macro definition.
    #define MAX 20
    void main()
    {
        int no=2,sq;
        for(int i=0;i
        {
            sq=no*no;
            printf("\nSquare of %d is %d",no,sq);
            no++;
        }
    }

    Points to remember
    1. When the program in compiled it is scanned by the preprocessor to check whether it contains any macro
    definitions(#define).If there are, it searches for the macro templates in the entire program. When it finds a template it replaces the macro template with the the macro expansion(value). Once the replacement is over the program is sent for compilation.
    2. The macro names are normally written in capitals to make them easily readable for the programmers. However,the same can be written in small letters also.
    3. There should be a space or a tab between the macro template and the macro expansion. A space between # and define is optional.
    4. A macro definition is never terminated by a semicolon.

    Why do we use #define ?
    There are two main reasons for why we use #define,
    a) To make the program easier to read : Using a macro, we can make a program easier to read. Consider this, suppose the phrase “d20@#” causes the screen to pause. But wouldn't it be easier if we can write "PAUSE" instead of "d20@#". So the macro would be defined as

    #define PAUSE d20@#

    b) If a constant like 365(days in a year) appears multiple times in the program and you want to change its value to 366. To do this you will have to read all the lines of the program and make changes at each occurence of 365. This will consume a lot of time and effort. But if we define a macro for the same, then changing the macro definition will change the value everywhere the preprocessor has been used.
    #define DAYS 365


    Why not use a variable ?
    If you think that we could have used a variable instead of a macro to do the same job, you are to an extent correct but not fully because using macros instead of variables has its own advantages:

    1. Macros are processed much faster than the variables.
    2. When you don't want to change the value of a variable then it is not recommended to declare it as a variable. It will make the program a bit difficult to understand.

    Examples


    #define AND &&
    void main( )
    {
        int age,exp;
        age=45;
        exp=4;
        if(age>25 AND exp>2)
            printf("\nYou will be considered for promotion");
        else
            printf("\nWait for some more time...");
    }
    • A #define directive could be used even to replace a condition, as shown below.

    #define PASS (marks>40 && marks<=100 )
    void main( )
    {
    int marks = 50 ;
    if ( PASS )
    printf ( "Congrats ! You have passed" ) ;
    else
    printf ( "Sorry try again" ) ;
    }
    • A #define directive could be used to replace even an entire C statement. This is shown below.
    #define MESSAGE printf ( "Let's learn macros" ) ;
    void main( )
    {
        MESSAGE;
    }

    Tuesday, December 14, 2010

    C header files

    Header file is defined as a "collection of functions of similar type". In C there are many inbuilt or library functions like "printf(), scanf(), strcmp(), getch()" etc. Each of these function is defined in the C library in a header file. For example the string functions are defined in the header file "string.h" , whereas mathematical functions are given in the header file "math.h". When the user writes any of these functions, the compiler reads the definition from the included header file and knows what this function is , how does it work etc.
    In C applications are divided into smaller parts through the use of header files.Any function prototype, and type definitions that can be exported from a source code file are put in a header file. From the point of view of the main application, these functions are external.The compiler reads the included header file and knows where a particular function comes from. Without this it would just report an undefined function error.In C a header file has the extension ".h" which denotes that is a header file. Following are the most used header files along with their description
    Contains defined constants specifying the implementation-specific properties of the floating-point library, such as the minimum difference between two different floating-point numbers, the maximum number of digits of accuracy (_DIG) and the range of numbers which can be represented (_MIN, _MAX).
    Header File Name Description

    assert.h
    Contains the assert macro, used to assist with detecting logical errors and other types of bug in debugging versions of a program.
    complex.h A set of functions for manipulating complex numbers.
    ctype.h Contains functions used to classify characters by their types or to convert between upper and lower case in a way that is independent of the used character set

    errno.h
    For testing error codes reported by library functions.
    float.h
    inttypes.h For precise conversion between integer types.
    limits.h Contains defined constants specifying the implementation-specific properties of the integer types, such as the range of numbers which can be represented (_MIN, _MAX).

    locale.h
    For setlocale and related constants. This is used to choose an appropriate locale.
    math.h For computing common mathematical functions.
    setjmp.h Declares the macros setjmp and longjmp, which are used for non-local exits.
    signal.h For controlling various exceptional conditions.
    stdarg.h For accessing a varying number of arguments passed to functions.
    stdbool.h For a boolean data type.
    stdint.h For defining various integer types.
    stddef.h For defining several useful types and macros.
    stdio.hProvides the core input and output capabilities of the C language. This file includes the venerable printf function.
    stdlib.h For performing a variety of operations, including conversion, pseudo-random numbers, memory allocation, process control, environment, signalling, searching, and sorting
    string.h For manipulating several kinds of strings.
    time.h For converting between various time and date formats.

    Friday, December 10, 2010

    Database management (Record Management)

    After learning all the operations in bits, let's now try to combine all the concepts to create a complete program. The first example we will are going to make is an "Employee Management Program". This program will give the user the option to "add,display,search and delete an employee". All the operations are performed using different functions. For example, to add a record we have used the "add_emp()" function and to display the list of employees the "show_emp()" function has been used. Since this is the first example of managing records, I've tried to keep it as simple as possible. Read the code carefully and then read the description to understand how the code works.


    Example 1 : Basic employee management program using binary file handling functions.

    #include
    #include
    #include // for strcmp()
    struct employee
    {
    int empno,salary;
    char ename[15];
    float tax,netsal;
    }
    // Public section
    employee emp;
    FILE *fptr;
    void main()
    {
    clrscr();
    // Function Prototyping
    void add_emp(); // to add a new emp
    void show_emp(); // to display all emp
    void search_emp(); // to search an emp
    void del_emp(); // to delete an emp
    char c;
    do
    {
    // Main menu
    printf("\na. Add New Employee Information");
    printf("\nb. Show all employees");
    printf("\nc. Search an employee");
    printf("\nd. Delete employee data");
    printf("\ne. Exit");
    fflush(stdin);
    printf("\nSelect an option (a/b/c/d/e) : ");
    scanf("%c",&c);
    if(c=='a' || c=='A')
    add_emp();
    else if(c=='b' || c=='B')
    show_emp();
    else if(c=='c' || c=='C')
    search_emp();
    else if(c=='d' || c=='D')
    del_emp();
    }while(c!='e' && c!='E');
    fclose(fptr);
    }
    void add_emp()
    {
    clrscr();
    fptr=fopen("emp_data","a"); // opens the file in append mode
    printf("\nAdd Employee");
    printf("\n-+-+-+-+-+-+-+-+-");
    char c;
    do
    {
    printf("\nEnter employee no. : ");
    scanf("%d",&emp.empno);
    printf("\nEnter employee name : ");
    scanf("%s",&emp.ename);
    printf("\nEnter basic salary : ");
    scanf("%d",&emp.salary);
    // Calculating tax and net salary
    emp.tax=emp.salary*3/100;
    emp.netsal=emp.salary-emp.tax;
    fwrite(&emp,sizeof(employee),1,fptr); // writing the data to the file
    fflush(stdin);
    printf("\nNew Record Added");
    printf("\nWould you like to add more records (y/n) : ");
    scanf("%c",&c);
    clrscr();
    }while(c=='y');
    fclose(fptr);
    }
    void show_emp()
    {
    clrscr();
    fptr=fopen("emp_data","r");
    while(fread(&emp,sizeof(employee),1,fptr)==1) // reading the file till tne end
    {
    printf("\nEmployee number %d",emp.empno);
    printf("\nEmployee name %s",emp.ename);
    printf("\nBasic Salary %d",emp.salary);
    printf("\nIncome tax %.2f",emp.tax);
    printf("\nNet Salary (After deducting tax) : %.2f",emp.netsal); // %.2f will show only 2 decimal points
    printf("\n===++++====++++====++++=====+++++"); // just a seperator (optional)
    }
    fclose(fptr);
    }

    void search_emp()
    {
    clrscr();
    int choice,eno,flag;
    char enm[12];
    fptr=fopen("emp_data","r");
    // asking the user to select a choice
    printf("\nSearch employee");
    printf("\n1. Search by empno");
    printf("\n2. Search by name");
    printf("\nSelect a criteria (1/2) : ");
    scanf("%d",&choice);
    if(choice==1)// if searching is by empno
    {
    clrscr();
    printf("\nSearch by empno ");
    printf("\n==================");
    printf("\nEnter empno to search : ");
    scanf("%d",&;eno);
    while(fread(&emp,sizeof(employee),1,fptr)==1) // reading the records
    {
    if(emp.empno==eno)// comparing the empno with the value entered by the user
    {
    printf("\nEmployee Data Found");
    printf("\n-------------------");
    printf("\nEmpno %d",emp.empno);
    printf("\nEmp name %s",emp.ename);
    printf("\nSalary %d",emp.salary);
    printf("\nIncome tax %.2f",emp.tax);
    printf("\nNet Salary %.2f",emp.netsal);
    flag=1; // marking the presence of the record
    }
    }
    if(flag!=1)
    printf("\nEmpno %d not found",eno);
    }
    else if(choice==2) // searching by name
    {
    clrscr();
    printf("\nSearch by emp name ");
    printf("\n==================");
    printf("\nEnter emp name to search : ");
    scanf("%s",&enm);
    while(fread(&emp,sizeof(employee),1,fptr)==1)
    {
    if(strcmp(emp.ename,enm)==0) // comparing the names using strcmp
    {
    printf("\nEmployee Data Found");
    printf("\n-------------------");
    printf("\nEmpno %d",emp.empno);
    printf("\nEmp name %s",emp.ename);
    printf("\nSalary %d",emp.salary);
    printf("\nIncome tax %.2f",emp.tax);
    printf("\nNet Salary %.2f",emp.netsal);
    flag=1;
    }
    }
    if(flag!=1)
    printf("\nEmp name %s not found",enm);
    }
    printf("\nPress any key to continue..");
    getch();
    clrscr();
    }
    void del_emp()
    {
    clrscr();
    int choice,eno,flag;
    char enm[12];
    FILE *fptr2;
    fptr2=fopen("temp","w"); // creating a temp file in writing mode
    fptr=fopen("emp_data","r");
    printf("\nSearch employee");
    printf("\n1. Delete by empno");
    printf("\n2. Delete by name");
    printf("\nSelect a criteria (1/2) : ");
    scanf("%d",&choice);
    if(choice==1)
    {
    clrscr();
    printf("\nDelete by empno ");
    printf("\n==================");
    printf("\nEnter empno to delete : ");
    scanf("%d",&eno);
    while(fread(&emp,sizeof(employee),1,fptr)==1)
    {
    if(emp.empno!=eno) // copying all the records in the temp file except the one to be deleted
    {
    fwrite(&emp,sizeof(emp),1,fptr2);
    }
    }
    }
    else if(choice==2)
    {
    clrscr();
    printf("\nDelete by emp name ");
    printf("\n==================");
    printf("\nEnter emp name to delete : ");
    scanf("%s",&enm);
    while(fread(&emp,sizeof(employee),1,fptr)==1)
    {
    if(strcmp(emp.ename,enm)!=0)
    {
    fwrite(&emp,sizeof(emp),1,fptr2);
    }
    }
    }
    printf("\nRecord Deleted");
    printf("\nPress any key to continue..");
    fclose(fptr);
    fclose(fptr2);
    remove("emp_data");//deleting the original file
    rename("temp","emp_data");// renaming the file to restore the original file
    getch();
    clrscr();
    }


    Description (Function wise)

    Public Section (The area just below the inclusion of header files)

    In the public section we have created two variables - "emp" which is an object of the structure "employee" and "fptr" which is a FILE pointer. The reason for declaring these variable here is that since all the functions of the program will be needing them, it will be very time consuming to declare them individually in each of the functions. Global variables like "emp" and "fptr" can be accessed by any of the functions of the program.

    main()

    The main() offers the user five choices in the form of - add,display,search,delete and exit. The user will type the appropriate alphabet to select an option, for example to add a new employee the choice is "a", "b" is to display etc. The program will proceed to call the functions given below as per the choice made. The menu is written inside a while loop, therefore whenever the control returns from a function it will stay in the main() displaying the choices again. The program will stop displaying choices when the user enters "e" to exit.

    add_data()

    The "add_data()" function opens the "emp_data" file in append ("a") mode. If the file is not already created, the program will create a new file. The user is asked to enter the employee's information like "empno,ename,salary" etc. Two values "tax" and "netsal" are calculated by the program instead of asking them from the user. All these values are stored in the file using "fwrite()" function. If the user wishes to add more records he/she can enter "y" when asked whether to continue or not. If the user enters "n" for NO, the program will return to the main function.

    show_data()

    This function is used to display all the records of the file. In the beginning, the file is opened in the "read" mode. Since the data was written in binary form through the "fwrite()" function, only the "fread()" can read it. A while loop reads the file from the beginning till the end. If you remember the "fread()" function returns "1" if the data is found. Therefore the loop will continue as long as the condition is true.

    search_data()

    To search a specific record, the user has two options - by empno or by name. If the user opts to search by empno by entering "1" when asked, the program will ask the user to enter the empno which is to be searched. Suppose the empno entered are "1,2,3,4,5" and the user wants to delete the record of empno "3", the user will enter "3" to delete this record. The "while" loop will start reading the records from the beginning till the end of the file. The first record read will be "1", the if condition(if emp.empno==eno) will result in false and the loop will proceed to read the second record. This time the comparison will be between the empno of the second employee(2) and 3, since the condition is false again the loop will continue to read the next record. The next record is of empno "3" which is the record that we want to search, the "if" condition will become true, and the details of the 3rd employee will printed on the screen.
     If the user enters "2" to search by name, the same process happens but comparing the names this time. The name entered by the user will be compared against all the names inside the file. The moment the name read from the file matches the name entered by the user the program will display all the details of the employee.

    del_data()
    Like "search_data()" the user is again given two choices - delete by empno or by name. Before deleting the specified record we must learn how the data is going to be deleted. We can not delete the record directly from the original file, instead of this we will copy all the records from the original file, except the record that we want to delete, to a temporary file. For example, if the user wants to delete the record of empno "5", all the other records(1,2,3,4) will be copied to a temporary file. Now the other file contains all the records except the one which was to be deleted. After the copy is over, the original file will be deleted, and the temporary file will be renamed to the name of the original file.
    Take a look at the code, after asking the user which record to delete, the loop copies those records which are not equal to the record that is to be deleted "if(emp.empno!=eno)". Once all the records are copied to the temporary file, both the files are closed and the original file("emp_data") is deleted. With the deletion of this file all the records are also deleted. Since all the other functions are using the name of the original file and we have deleted it, it will create the program to show errors because the file does not exists any more. Therefore to complete the deletion process we have renamed the temporary file ("temp") to the original file name ("emp_data").







    

    fprintf( ) and fscanf( )

    Input output functions that were declared in earlier sections were quite useful, but in addition to that we can use two more functions - "fprintf()" and "fscanf()". As the names suggest both the functions are similar to "printf()" and "scanf()" which are basic Input/Output functions. The difference is that "fprintf()" and "fscanf()" work with files only. This function is similar to printf(), except that a FILE pointer is included as the first argument. As in printf( ), we can format the data in a variety of ways, by using fprintf( ). In fact all the format conventions of printf( ) function work with fprintf( ) as well.


    Syntax :
    int fprintf(FILE *fp, const char *control_string, . . .);
    int fscanf(FILE *fp, const char *control_string, . . .);

    Although fprintf() and fscanf() often are the easiest way to write and read formatted data to disk files, they are not always the most efficient. Because formatted ASCII data is being written as it would appear on the screen (instead of in binary), extra overhead is incurred with each call. Therefore to run the program speedily we should use fread() and fwrite().


    Example 1 : Using fprintf() and fscanf()

    #include
    #include
    #include // For exit()
    void main()
    {
    FILE *fp; // Line 1
    char str[30]; // Line 2
    int t; // Line 3
    if((fp=fopen("myfile", "w")) == NULL) // Line 4
    { // Line 5
    printf(''File Can Not Be Created !!"); // Line 6
    exit(1); // Line 7
    } // Line 8
    printf("Enter some text and a digit "); // Line 9
    fscanf(stdin, "%s%d", s, &t); // Line 10
    fprintf(fp, "%s %d", s, t); // Line 11
    fclose(fp) // Line 12
    if((fp=fopen("test","r")) == NULL) // Line 13
    { // Line 14
    printf("Error in opening file"); // Line 15
    exit(1); // Line 16
    } // Line 17
    fscanf(fp, "%s%d", s, &t); //Line 18 -- Reading data from the file in %s(string) and %d(int) format
    fprintf(stdout, "%s %d", s, t); // Line 19 -- Printing the data on the screen.
    }

    Description

    The above program reads a string and an integer from the keyboard and writes them to a file called MYFILE. The program then reads the file and displays the information on the screen. After running this program, examine the MYFILE.

    Line 4,6 and 7
    Tries to create/open a file in "write(w)" mode. If due to any reason the file can not be created, the "fopen()" function will return NULL. The program will exit.message after displaying the message "File can not be created".
    Line 9
    Will ask the user to enter some text and a digit.
    Line 10
    The "fscanf()" function will accept the data in %s and %d format.
    Line 11
    The "fprintf()" will "print" (write) both the values to the file. The first argument is the file pointer to which we want to write the data, where as the second and third arguments are the formats in which we want to write the data.
    Line 12
    Will close the file from "writing" mode.
    Line 13
    To read the file, the file is opened using "fread()". If the system is unable to open the file in read mode the file pointer will again return NULL and the program will exit again after printing the message "Error in opening file".
    Line 18
    If the file opens sucessfully, the fscanf() function will read the data from the file. Note that the format in which the data is to be read is specified again.
    Line 19
    The read data is printed on screen. The first argument "stdout" specifies that the data is to be printed to the "Standard Output" device which is "monitor".

    Thursday, December 9, 2010

    Random Access in a file

    Files in a computer system are accessed in two ways

    1. Sequentially : This is the default behavior of the system. Sequential access is the method in which the data of the file is accessed in a serialized way. If the program is to read a file, the data will be read from the first char or byte to the second byte and so on. For example , if the file contains the data "abcdefghi", "a" will be accessed the first, followed by "b", "c" and so on. Similarly if the program is writing the data in the file then it will first write "a", followed by "b","c" and so on. The sequential file access method is fine  for reading a file which will make sense only if the data is read sequentially. The disadvantage of this method is that if you want read a particular portion of the file, you can not jump to a specific point(position) and start reading from there. In the same way, if you want to write data at a particular position you can not do it since sequential access does not allow writing at any random position.

    2. Randomly : Random access is the method whereby a file can be read from or written to any position in the file. This method is quite useful where we want to skip some data and read only the desired part. Take the program of any media player for example, when you are watching a movie and you want to move forward some scenes that you have already seen, you can easily move the given "slider" and drop it at the point from where you want to continue watching. This is very useful method during file management because you don't to waste your time and memory in traversing the data that you don't want to see. Random access file handling only accesses the file at the point at which the data should be read or written, rather than having to process it sequentially.

    Random File Handling Function

    To handle a file randomly the function used are

    1. rewind() – The "rewind()" function positions the file pointer at the beginning of the file. It does not matter where the pointer is while using this function. The "rewind()" function will place the pointer to byte no. 0 (beginning) even if it was at the end, middle or anywhere else.
    Syntax
        rewind(filepointer);
    Example   
        rewind(fp);

    2. fseek() – To move to any particular position in a file "fseek()" is used. This function can move the cursor at any desired location.
    Syntax
        fseek(file pointer, bytes to move,start position or origin)
     Where    
        file pointer - is the file in which we want to access the data randomly.
        bytes to move - is the number of bytes that we want to move. It is given in "long" format.
        Start Position or origin - The point from where we want to move. It can take the following parameters
            0 - Move from beg. of the file
            1 - Move from the current position
            2 - Move from the end of the file.


        For example if want to move to the 5th byte from the beginning, the "fseek()" function will look like
            fseek(fp,5,0); // 0 denotes that we want to move from the beginning.

            Similarly to move 20 bytes from the beginning, we can use   
            fseek(fp,20,0);

        If we want the movement to happen from the current position of the cursor, we will change the third argument to 1
            fseek(fp,10,1); // Will move 10 bytes forward from the current position.
        to move backwards, the second argument will a negative number

            fseek(fp,-30,1) ;// Will move 30 bytes backwards from the current position

        To move from the end, we will write 2 as the third argument, while the second argument will be a negative number.
            fseek(fp,-25,2);//Will move 25 bytes backwards from the end of the file

        As you can see, when we are moving from the beginning of the file, the second argument should be a positive number since you can not move backwards from the beginning of the file. In the same way if you are making a move from the end, the second argument will always be a negative number since you can not move forward from the end. The only exception is while moving from the current position. While moving from the current position you can write both positive and negative values since you can make a move in both the directions.   
    3. ftell() – If we want to check the current offset (cursor) position in a file, we can use the "ftell()" function. This function returns the current position of the cursor.
    Syntax
        int ftell(filepointer);
    Example
        int pos;
        pos=ftell(fp);

       
        If the "ftell()" function is applied right after opening the file, it will return 0 since we haven't read the data or used the "fseek()" function.

    Wednesday, December 8, 2010

    Reading Binary Files

    Let's try to read the files we created in previous articles using "fwrite()", function. As I told you, you can not read or open a file written using "fwrite()" by any method other than using the "fread() function. The syntax of "fread()" is similar to the "fwrite()" function. fread( ) function causes the data read from the disk to be placed in the structure variable specified within the syntax. The function "fread()" returns the number of records read. Ordinarily, this should correspond to the third argument, the number of records we asked for... 1 in this case. When there are no more records to be read means we have reached the end of file, since fread() cannot read anything, it returns a 0. By testing for this situation, we know when to stop reading.So let's see how a binary file will be read. We will be reading the same files one by one.

    Example 1 : Reading the "list" file , created in example 1 in the previous post

    #include
    #include
    struct person
    {
    char name[12];
    int age;
    };


    void main()
    {
    clrscr();
    FILE *fp;
    fp=fopen("list","w");
    person p;
    printf("\nEnter name ");
    scanf("%s",&p.name);
    printf("\nEnter age ");
    scanf("%d",&p.age);
    fwrite(&p,sizeof(person),1,fp);
    printf("\n1 person added");
    fclose(fp);
    // Reading starts from here
    fp=fopen("list","r");
    fread(&p,sizeof(person)1,fp); // reading the data using the fread() function
    printf("\nHere is the data entered in the file...");
    printf("\nName : %s",p.name);
    printf("\nAge : %d",p.age);
    fclose(fp);
    }

    Description
    The writing part is same as given earlier. When it comes to reading the file, the "fread()" reads the data of the file(name and age) and stores it to the object "p". When we print the values of "p.name" and "p.age", it will print the data which was there in the file. How does "fread()" know how many records to read? There are two things to remember before answering this question, first - since we have written "fread()" just once, it will perform the read operation just once, and secondly "fread()" does not read records, it reads "bytes". How many bytes constitue a record has been informed to it by using the "sizeof" operator. We are telling the "fread()" function to read "sizeof" amount of bytes from the file. In this example the size of one record is 14 bytes (12 bytes for name,2 bytes for age), therefore the "fread()" function will read the first 14 bytes from the file. The first bytes will form the data of the first person.


    Example 2 : Reading the "library.dat" file, created in example 2 in the previous post.
    #include
    #include
    struct books
    {
    int bookno,price;
    char name[12],pub[20];
    };
    void main()
    {
    clrscr();
    char c;
    FILE *fp;
    fp=fopen("library.dat","a");
    books b;
    do
    {
    printf("\nBook no ");
    scanf("%d",&b.bookno);
    fflush(stdin);
    printf("\nEnter book name ");
    gets(b.name);
    printf("\nEnter publisher ");
    gets(b.pub);
    printf("\nEnter book price ");
    scanf("%d",&b.price);
    fwrite(&b,sizeof(books),1,fp);
    fflush(stdin);
    printf("\nNew book added to library.");
    printf("\nPress Y to add more books, N to Close : ");
    scanf("%c",&c);
    }while(c=='Y' || c=='y');
    fclose(fp);
    fp=fopen("library.dat","r");
    while(fread(&b,sizeof(books),1,fp)==1) // reading book data one record at a time
    {
    printf("\nBook no %d",b.bookno);
    printf("\nBook name %s",b.name);
    printf("\nPublisher %s",b.pub);
    printf("\nPrice %d",b.price);
    printf("\n-----------------------------------"); // Just a seperator, two differntiate between 2 records optional)
    }
    fclose(fp);
    }

    Description
    Since there are multiple records in this file and we don't know how many records have been entered by the user, we'll to put the "fread()" function inside a while loop. Remember that fread returns 1 if it finds data in the file and 0 if there is no data to be read, therefore we have written the condition "while(fread)==1", so that the loop continues to read the data till the end of the file. When all the data has been read, the "fread()" function will return 0 and the loop will terminate. All the records are printed by one by one with an optional seperator between each record.


    Example 3 - Reading the "school" file, created in example 3 in the previous post.

    #include
    #include
    struct student
    {
    int rollno,marks1,marks2,marks3,total,avg;
    char name[10];
    };
    void main()
    {
    student s;
    FILE *fptr;
    fptr=fopen("school","a");
    char ch;
    int i;
    for(i=0;i<5;i++)
    {
    printf("\nRollno ");
    scanf("%s",&s.rollno);
    printf("\nName ");
    scanf("%s",&s.name);
    printf("\nMarks 1 ");
    scanf("%d",&s.marks1);
    printf("\nMarks 2 ");
    scanf("%d",&s.marks2);
    printf("\nMarks 3 ");
    scanf("%d",&s.marks3);
    s.total=s.marks1+s.marks2+s.marks3;
    s.avg=s.total/3;
    fwrite(&s,sizeof(student),1,fptr);
    printf("\nSaved in the file");
    }
    fclose(fptr);
    fptr=fopen("school","r");
    while(fread(&s,sizeof(student),1,fptr)==1)
    {
    printf("\nRollno %d",s.rollno);
    printf("\nName %s",s.name);
    printf("\nMarks 1 %d",s.marks1);
    printf("\nMarks 2 %d",s.marks2);
    printf("\nMarks 3 %d",s.marks3);
    printf("\nTotal marks %d",s.total);
    printf("\nAverage %d",s.avg);
    printf("\nPress any key to continue ...");
    getch();
    }
    fclose(fp);
    }


    Description
    The reading process is same as that of example 2. Here we have added an "Press any key" message also so that the user can pause the screen after each record.

    Writing a file in binary mode

    To write a binary file the function that we will use is "fwrite()".  The "fwrite()" function can write binary data to a file.

    Syntax
        fwrite(&data,sizeof_data,no_of_rec,filepointer)
       
    Here, the first argument is the address of the structure or variable which we want to write to the file. The second argument is the size of the structure in bytes. We can calculate the size manually(int 2 byes, float etc), but this approach is not recommended since the size of data type depends on the processor.  Therefore instead of calculating it ourselves, we use the "sizeof()" operator to do the same. The sizeof( ) operator gives the size of the variable in bytes. This will help us in 2 ways - first, we won't have to perform  the calculations manually, and secondly if the datatype of the data to be written is changed, we don't need to make changes in the program.The third argument is the number of such structures that we want to write at one time. In this case, we want to write only one structure at a time. Had we had an array of structures, for example, we might have wanted to write the entire array at once.The last argument is the pointer to the file we want to write to.


    Example 1 : Writing a record to a file

    #include
    #include
    struct person
    {
        char name[12];
        int age;
    };
    void main()
    {
        clrscr();
        FILE *fp;
        fp=fopen("list","w");
        person p;
        printf("\nEnter name ");
        scanf("%s",&p.name);
        printf("\nEnter age ");
        scanf("%d",&p.age);
        fwrite(&p,sizeof(person),1,fp);
        printf("\n1 person added");
        fclose(fp);
    }

    Description

    The above program is a basic example of how the data of a structure(record) can be saved to a file. The program starts with a structure declaration with two member variables, name and age. In main, we have created an object of the structure "person" with the name "p". If you remember, we can not access the structure variables directly. We must create an object to access all the members using the "objectname.membername" notation, for example "p.name". When all the values have been entered by the user, we will not write "name" and "age" in the file separtely since both of them are inside the object "p". If we can somehow write the value of "p" in the file both "name" and "age" will be saved.
    To save the data in binary format the function "fwrite()" has been used. "fwrite()" has been given 4 arguments.
    • First argument (&p) : is the address of the object that has to be saved in the file. It will contain all the values that were present in the structure.
    • Second argument (sizeof(person)) : is the size of memory that will be required to save this data. The "sizeof" operator will automatically calculate the memory occupied by the structure.
    •     Third argument (1) : is the number of structures that we want to write. Since we want to write only one structure at time 1 is written.
    •     Fourth argument (fp) : is the file pointer in which we want to store the data.


    After running this program, try to read the file "list" using any method. You will see that the data printed will not be readable. Why is it so? because the file has been written the using the binary function "fwrite()". The data has been written in binary format which can not be read directly. We will learn about reading such files later.

    Example 2 : Writing multiple records to a file

    #include
    #include
    struct books
    {
        int bookno,price;
        char name[12],pub[20];
    };
    void main()
    {
        clrscr();
        char c;
        FILE *fp;
        fp=fopen("library.dat","a");
        books b;
        do
        {
        printf("\nBook no ");
        scanf("%d",&b.bookno);
        fflush(stdin);
        printf("\nEnter book name ");
        gets(b.name);
        printf("\nEnter publisher ");
        gets(b.pub);
        printf("\nEnter book price ");
        scanf("%d",&b.price);
        fwrite(&b,sizeof(books),1,fp);
        fflush(stdin);
        printf("\nNew book added to library.");
        printf("\nPress Y to add more books, N to Close : ");
        scanf("%c",&c);
        }while(c=='Y' || c=='y');
        fclose(fp);
    }


    Description
        Logically, this program is similar to the previous "person" program. The only new thing we have done here is that we have written the "fwrite()" function inside the loop. This will allow the user to enter as many records as needed.


    Till now what we have written to the files is entered by ther user himself. Sometimes, there can be a condition that we want to accept some data from the user and some values are to be calculated.Let's make a program to do so.
    Example 3 - Writing calculated values to the file

    #include
    #include
    struct student
    {
        int rollno,marks1,marks2,marks3,total,avg;
        char name[10];
    };
    void main()
    {
        student s;
        FILE *fptr;
        fptr=fopen("school","a");
        char ch;
        for(int i=0;i<5;i++)
        {
            printf("\nRollno ");
            scanf("%s",&s.rollno);
            printf("\nName ");
            scanf("%s",&s.name);
            printf("\nMarks 1 ");
            scanf("%d",&s.marks1);
            printf("\nMarks 2 ");
            scanf("%d",&s.marks2);
            printf("\nMarks 3 ");
            scanf("%d",&s.marks3);
            s.total=s.marks1+s.marks2+s.marks3;
            s.avg=s.total/3;
            fwrite(&s,sizeof(student),1,fptr);
            printf("\nSaved in the file");
        }
        fclose(fptr);
    }


    Description
    In this program we are writing the data of 5 students using a for loop. A student record has 7 values rollno,name,marks1,marks2,marks3,total and average. Out of these 7 values, 5 are being entered by the user and 2 are being calculated by the program. Total is calculated by adding all three marks, whereas avg has been achieved by dividing the total by 3. When we write the data using "fwrite()", we are writing the value of "s" which has 7 values in total, 5 entered by the user and 2 calculated values. In this way we can store customized values to the file.

    Monday, December 6, 2010

    Text and a Binary file

    As mentioned earlier files are required to store information permanently for future use. The files can be stored in two ways

    1. Text Files : Text Files store information in ASCII codes. In text files, each line of the text ends with a special character known as the "End of Line" character (EOL).

    2. Binary Files : A binary file is just a file that contains information in the same format in which the information is held in memory. In binary file, there is no delimiter for a line. Also no translations occur in binary files. As a result, binary files are faster and easier for program to read and write than text files. If the file is not needed to be read by a person directly, binary file are the best way to store program information. A binary file is a file of any length that holds bytes with values in the range 0 to 0xff. (0 to 255). These bytes have no other meaning unlike in a text file where a value of 13 means carriage return, 10 means line feed, 26 means end of file and software reading text files has to deal with these. In modern terms we call binary files a stream of bytes and more modern languages tend to work with streams rather than files.How would you know that a file is a text file or a binary file? It's simple. Just try to open the file in any editor like "Notepad" in Windows. If the file opens successfully and you can read the data easily, it's a text file otherwise a binary file.

    Difference between a text and a binary file

    1. A text file can be easily opened in an editor, whereas a binary file can not be.In C, when you create a binary file you can't read it in the normal way. This means that if a file was created using binary writing function you won't be able to open it using DOS Shell or the File -> open methods (given in the previous posts). Then how would you read such a file? The only method to read a binary file is by creating a program for "Binary Reading".
    2. In text files, a special character whose ASCII value is 26 is automatically added to the end of the file. This mark is called the end of file (EOF) marker. When we create a program to read a text based file, it is this symbol which is searched. As soon as this symbol is reached "end of file" is assumed. Opposite to this in binary files, the size of the file is determined from the file's entry in the OS's directory and file table. If a file has been written in text mode it should be read in text mode only. Similarly if a file was created in binary mode, the same should be used for reading.
    3. In text mode, a newline character ("\n") is converted into the carriage return-linefeed combination before writing it to the disk. Similarly, the carriage return-linefeed combination on the disk is converted back into a newline when the file is read in text mode. But, if a file is opened in binary mode these conversions will not take place.
    4. In text mode, to write numbers in a file, the function available is "fprintf()". The "fprintf()" function stores numbers as string rather that integers. Therefore if you write the values 19567which would have taken 2 bytes as integer will take 5 bytes if written through "fprintf()". This means more memory will be required to even more large numbers. Contrary to this binary functions store data in binary mode which consumes the same amount of disk space as it does in memory.

    A data entry program

    A data entry program which reads and writes the data using different functions.

    #include
    #include
    #include
    FILE *fp; // public variable fp. It can now be accessed in all the functions of the program.
    void main()
    {
        clrscr();
        void write();
        void read();
        int c;
        do
        {
            printf("\n C O M P U T E R -- Q U I Z ");
            printf("\n ===========================");
            printf("\n1. New Test");
            printf("\n2. List of appeared candidates");
            printf("\n3. Exit");
            printf("\nSelect an option ");
            scanf("%d",&c);
            if(c==1)
                write();
            else if(c==2)
                read();
        }while(c!=3); // Run till the user enters 3 to exit the program.
    }
    void write()
    {

        int marks=0,c;
        char name[10],doe[10],result[12],choice;
        fp=fopen("exam.txt","a");
        do
        {
            clrscr();
            printf("\nCandidate Details");
            printf("\n-----------------");
            printf("\n\nCandidate Name : ");
            scanf("%s",&name);
            printf("\nDate of exam : ");
            scanf("%s",&doe);
            printf("\nPress any key to start the quiz..");
            getch(); // to pause the screen
            clrscr();
            printf("\nQ1. What is the full form of CPU ? ");
            printf("\n1. Central Processing Unit 2. Central Power Unit");
            printf("\nEnter your choice ");
            scanf("%d",&c);
            if(c==1)
                marks+=10;
            printf("\nPress any key for the next question ...");
            getch();
            clrscr();
            printf("\nQ2. Which of the following is a temporary memory ? ");
            printf("\n1. ROM  2. RAM");
            printf("\nEnter your choice ");
            scanf("%d",&c);
            if(c==2)
                marks+=10;
            printf("\nPress any key for the next question ...");
            getch();
            clrscr();
            printf("\nQ3. Which company makes Windows ? ");
            printf("\n1. Oracle Corp. 2. Microsoft Corp.");
            printf("\nEnter your choice ");
            scanf("%d",&c);
            if(c==2)
                marks+=10;
            printf("\nPress any key for the next question ...");
                getch();
            clrscr();
            printf("\nQ4. Which of the following is not an Operating System ? ");
            printf("\n1. Java           2. Linux");
            printf("\nEnter your choice ");
            scanf("%d",&c);
            if(c==1)
                marks+=10;
            printf("\nPress any key for the next question ...");
            getch();
            clrscr();
            printf("\nQ5. Which of the following is an Object Oriented Language ? ");
            printf("\n1. C++         2. C");
            printf("\nEnter your choice ");
            scanf("%d",&c);
            if(c==1)
                marks+=10;
            printf("\nPress any key to finish the quiz ...");
                getch();
            clrscr();
            printf("\n Finished");
            // Result is determined as per the marks scored.
            if(marks>=0 && marks<=20)
                strcpy(result,"Fail");
            else if(marks>=30 && marks<=40)
                strcpy(result,"Good");
            else
                strcpy(result,"Excellent");
            // Writing the data to the file exam.txt
            fputs("\nName ",fp); // Writing the heading first
            fputs(name,fp); // Writing the value of name
            fputs("\nExam Date ",fp);
            fputs(doe,fp);
            fputs("\nResult ",fp);
            fputs(result,fp);
            fclose(fp);
            fflush(stdin);
            printf("\nDo you want to conduct another test ? ");
            scanf("%c",&choice);
        }while(choice=='y'|| choice=='Y');

    }
    void read()
    {
        char line[15];
        fp=fopen("exam.txt","r");
        clrscr();
        printf("\nList of appeared candidates");
        printf("\n===============================");
        while(fgets(line,15,fp)!=NULL)
        {
            printf("%s",line);
        }
        fclose(fp);
        printf("\nPress any key to return to main menu ...");
        getch();
    }

    Description
    This is a basic computer quiz program. The program contains two functions namely write and read. The write function is used to write the candidate's details like name, date of exam etc. and saves them in the file. In main, we have asked the user to enter his choice - 1 for writing (taking the quiz) and 2 for reading (printing details of the appeared candidates). 
    The "Write" function
        The write function opens the file in "a" mode which means "append" mode. The "append" mode denotes that we want to write the details of all the candidates in the file one after the other without overwriting the previous data. If we use "w" mode in place of "a", it will overwrite the details of the previous candidates. Inside the function we are asking the user some basic questions. Each question has 2 options out of which the user has to choose the correct one. For each correct answer we are assigning 10 marks to the candidate by writing "marks+=10" after each question. Once all the questions have been answered, the total marks are calculated. "Result" is determined as per the result, "Excellent" for those who have scored full (50) marks and "Fail" for those who haven't given a single correct answer After the completion of the test, all the details which were entered by the user are saved in the file along with the result. Note that while writing the details we have used two "fputs()" per value.
    This has been done to save the data along with its heading. For example to write the value of "name", the first "fputs()" first writes "Name" as a heading after which the second "fputs()" writes the value of the variable "name". Similarly "doe" has been saved under the heading "Exam Date" and so on. The benefit of using double "fputs()" will be shown while reading the file, where each value will come after the heading. Like "Name Xyz","Exam Date 2-10-2010" etc.  You can easily skip the heading part if you want.The loop will ask the user to confirm whether he wants to continue or not. If the user chooses "y" the loop will run again, asking the user details again and quiz starts again. The details of each of the candidates will be saved in the file.
    The "Read" function
        The read function will print the details of all the candidates who have taken the test. It opens the file in "read" mode and starts printing the details using "fgets()" reading 15 bytes at a time. This will print all the contents of the file. The file is closed and the user is asked to press a key to continue.