C/contact mgmt system
Expert: Zlatko - 4/1/2011
QuestionQUESTION: sir i am preparing a project "contact managemant system". for this i am using structure to enter contact records into file.
sir I want to know how could I delete a particular single record from file.
ANSWER: Hello Pragya
The difficulty with deleting a record from a file is that the file does not reorganize itself to get rid of the hole left by the deleted record. You have to reorganize the file or somehow mark the space as available for future use. This can be tricky because it involves moving around the file using file pointers. The easiest way to delete a record is this:
1) create an empty temporary file
2) read in records from the original file and write them to the temporary file, except for the records you want deleted.
3) close both the original and the temporary file
4) delete the original file using the standard C unlink function
4) rename the temporary file to the original file name using the standard C rename function
See
http://msdn.microsoft.com/en-us/library/1c3tczd6.aspx
http://msdn.microsoft.com/en-us/library/zw5t957f%28v=vs.71%29.aspx
for information on unlink and rename.
Because unlink and rename are standard C library functions, they are available on all operating systems.
Best regards
Zlatko
---------- FOLLOW-UP ----------
QUESTION: Thankz sir for your response
Sir, please tell me the code for placing the pointer at particular contact record which is to be deleted. name field of the record which is to be deleted is taken from user
ANSWER: Hello
Please understand that in my earlier answer, with the temporary file, you do not need to move the file pointer around. The temporary file method is easy and, if the file is sorted, the method does not disturb the sort.
In C you can use fseek to move the file pointer to a particular location
Read
http://www.cplusplus.com/reference/clibrary/cstdio/fseek/ for an explanation and a sample.
You will need ftell to discover where the current file pointer is at. You can read about ftell at
http://www.cplusplus.com/reference/clibrary/cstdio/ftell/
You will need to know about _chsize on windows or ftruncate on Linux to change the size of a file.
See
http://msdn.microsoft.com/en-us/library/dk925tyb%28v=vs.80%29.aspx
and
http://pubs.opengroup.org/onlinepubs/007908799/xsh/ftruncate.html
Here is how to delete a record from the middle of the file. This method assumes that it is not bad to mix up the order of records in the file.
You will need to know the length of your record in bytes.
1) Read your file until the record to be deleted is found. When the record is read in, the file pointer will point to just past the record.
2) Use ftell to get the file pointer value. Subtract the record length from it and remember the value. The value represents the start position of the record to be deleted.
3) Use fseek to move the file pointer to the end of the file minus one record length. That will make the file pointer point to the start of the last record. Remember that file pointer location too.
4) Read the last record
5) Move the file pointer to the start of the record to be deleted. That is the location you remembered from step 2.
6) Write the last record to the current file pointer location. You have now overwritten the record to be deleted with the last record in the file. The file now has two instances of the last record.
7) Use _chzise or ftruncate to reduce the size of the file to remove the last record.
Show me your attempt and I will help you more.
Best regards
Zlatko
---------- FOLLOW-UP ----------
QUESTION: Sir this is code for entering the records in the file and finding the particular record using name field:
#include<stdio.h>
#include<conio.h>
struct cont{
char name[20];
char pno[15];
};
int main()
{
FILE *fp;
struct cont c;
char ch[20],mr='y';
int flag=0,i=0;
fp=fopen("cont.dat","a");
while((mr!='n')&&(mr!='N')){
printf("Enter name:");
scanf("%s",&c.name);
printf("Enter pno:");
scanf("%s",&c.pno);
fwrite(&c,sizeof(c),1,fp);
fflush(stdin);
printf("more records?(y or n):");
scanf("%c",&mr);
fflush(stdin);
}
fclose(fp);
fopen("cont.dat","r");
rewind(fp);
printf("Enter name to delete:");\\finding the contact to be deleted
scanf("%s",&ch);
while(fread(&c,sizeof(c),1,fp)){
if(c.name[0]==ch[0]){
while((c.name[i]!='\0')&&(ch[i]!='\0')&&(i<19)){
if(c.name[i]==ch[i]){
flag=1;
}
else{
flag=0;
}
i++;
}
}
if(flag==1){
printf("\n%s %s",c.name,c.pno);
break;
}
}
fclose(fp);
getch();
}
AnswerHello
The code below shows you how to do it with file pointers. I put comments into the code to explain the steps.
Best regards
Zlatko
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<io.h>
void deleteRecord(FILE* fp);
struct cont{
char name[20];
char pno[15];
};
int main()
{
FILE *fp;
struct cont c;
char ch[20],mr='y';
int flag=0,i=0;
fp=fopen("cont.dat","a");
while((mr!='n')&&(mr!='N')){
printf("Enter name:");
scanf("%s",&c.name);
printf("Enter pno:");
scanf("%s",&c.pno);
fwrite(&c,sizeof(c),1,fp);
fflush(stdin);
printf("more records?(y or n):");
scanf("%c",&mr);
fflush(stdin);
}
fclose(fp);
/* When opening again, make sure to assign the fp.
Open with r+, to allow reading and writing so that records
can be deleted.
*/
fp = fopen("cont.dat","r+");
printf("Enter name to delete:");//finding the contact to be deleted
scanf("%s",&ch);
while(fread(&c,sizeof(c),1,fp)){
/*
You dont need a complicated loop here to compare strings
Use the standard C library strcmp function. Always use the
standard library functions if available. Anyway, the loop
logic is incorrect. The flag should start out as 1, and as soon
as a character mismatch is found, flag should go to 0, and the
string comparison loop should quit. In your version, flag can switch
between 0 and 1 depending on the last character checked.
if(c.name[0]==ch[0]){
while((c.name[i]!='\0')&&(ch[i]!='\0')&&(i<19)){
if(c.name[i]==ch[i]){
flag=1;
}
else{
flag=0;
}
i++;
}
}
*/
flag = (strcmp(c.name, ch) == 0);
if(flag==1){
printf("\n%s %s\n",c.name,c.pno);
/* Now the file record has been found and we
want to delete it. Lets put the deletion into a separate
function
*/
deleteRecord(fp);
break;
}
}
fclose(fp);
printf("Done.\n");
getch();
}
/* Deletes the record at the current file pointer */
void deleteRecord(FILE* fp)
{
/* Simply follow the instructions which I gave you.
It't true that there are some tricky parts, but with some
experimenting you could get it.
*/
long recordToDeletePos; /* start position */
long lastRecordPos; /* start position */
struct cont lastRecord;
/* 2) Use ftell to get the file pointer value.
Subtract the record length from it and remember the value.
The value represents the start position of the record to be deleted.
*/
recordToDeletePos = ftell(fp) - sizeof(struct cont);
/* 3) Use fseek to move the file pointer to the end of the file minus
one record length. That will make the file pointer point to the
start of the last record. Remember that file pointer location too.
*/
fseek(fp, -sizeof(struct cont), SEEK_END);
lastRecordPos = ftell(fp);
/* 4) Read the last record
*/
fread(&lastRecord, sizeof(lastRecord), 1, fp);
/* 5) Move the file pointer to the start of the record to be deleted.
That is the location you remembered from step 2.
*/
fseek(fp, recordToDeletePos, SEEK_SET);
/* 6) Write the last record to the current file pointer location.
You have now overwritten the record to be deleted with the last record in the file.
The file now has two instances of the last record.
*/
fwrite(&lastRecord, sizeof(lastRecord), 1, fp);
fflush(fp);
/* 7) Use chzise or ftruncate to reduce the size of the file to remove the last record.
*/
chsize(fileno(fp), lastRecordPos);
}