Related
I am working on code for s blood donation system. I'm currently struggling with the delete donor record function.
The delete record function is to delete the record of a donor with a given name. If there are two or more records with the same name in the file then the program asks for mobile number. While there may be more than one person with the same name, each person has a unique mobile number.
My problem is that when the same name is used for several records, the wrong record is deleted.
If there's only one record with that name, the program deletes the record in the manner that's required.
(The variable i is declared globally as int i)
Here's the delete function
void delete(struct blood *b,int n)
{
char name[50];
int phone;
int found=0;
int c=0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
printf("\nEnter Name: ");
scanf("%s", name);
printf("---------------------------------------------\n");
while(fread(&b[i],sizeof(struct blood),1,fp))
{
if(strcmpi(b[i].name,name)==0)
{
c=c+1;
printf("\nName: %s\n",b[i].name);
printf("Age: %d\n", b[i].age);
printf("Mobile no.: %d\n", b[i].phone);
printf("Blood group: %s\n", b[i].bg );
printf("Weight: %d\n", b[i].weight);
printf("Sex: %s\n",b[i].sex);
printf("Address: %s\n",b[i].add);
printf("\n");
if (c==1)
{
found=1;
}
else if(c>1)
{
printf("\nThere are more than one occurences of this name in the records\n");
printf("\nPlease enter the mobile number of the donor: ");
scanf("%d", &phone);
if (b[i].phone == phone)
{
found=1;
}
}
}
else
fwrite(&b[i],sizeof(struct blood),1,fp1);
}
fclose(fp);
fclose(fp1);
if (found==1)
{
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b[i],sizeof(struct blood),1,fp1))
{
fwrite(&b[i],sizeof(struct blood),1,fp);
}
fclose(fp);
fclose(fp1);
}
else
{
printf("\n\aRECORD DOES NOT EXIST.\n");
}
printf("RECORD SUCCESSFULLY DELETED");
getchar();
getchar();
}
I suggest that to make the program simpler, you request both the donor's name and the donor's mobile number at the beginning.
Then you process the input file and look for both name and mobile number in a single pass.
I started with your code and made a few changes. See comments.
Please note that I have not tested this code nor compiled it. It should be essentially correct however there may be a compiler error if I made a syntax mistake.
I assume that the you are using the struct blood correctly in your code since you did not provide the code defining that struct.
I assume that an int is sufficiently large to hold the mobile number. Since the size of an int can vary and is determined by the compiler, it may or may not be large enough for a mobile number. See Range of values in C Int and Long 32 - 64 bits
One thing I do not understand is why you are using the b[i] syntax and where is the variable i defined? You could instead use a local variable in the delete() function.
I also have the delete() function returning a value indicating if it found a match or not. This may or may not be useful.
int delete()
{
struct blood b;
char name[50] = {0};
int phone;
int found = 0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
// Ask for the donor's mobile number along with their name
// at the beginning to make the search easier and be able to
// do this in a single pass.
printf("\nEnter Name of the donor: ");
scanf("%49s", name); // Oka's comments about scanf().
printf("\nPlease enter the mobile number of the donor: ");
scanf("%d", &phone);
printf("---------------------------------------------\n");
while(fread(&b, sizeof(struct blood), 1, fp))
{
// check both donor's name and donor's mobile number.
if(strcmpi(b.name, name) == 0 && b.phone == phone)
{
// print out the donor data and indicate we are deleting
// this donor record.
printf("Deleting donor record\n");
printf(" Name: %s\n", b.name);
printf(" Age: %d\n", b.age);
printf(" Mobile no.: %d\n", b.phone);
printf(" Blood group: %s\n", b.bg );
printf(" Weight: %d\n", b.weight);
printf(" Sex: %s\n", b.sex);
printf(" Address: %s\n", b.add);
printf("\n");
found = 1;
}
else {
// we are keeping this donor record so write it to the
// temp file.
fwrite(&b, sizeof(struct blood), 1, fp1);
}
}
fclose(fp);
fclose(fp1);
if (found == 1)
{
// file temp.txt has deleted donors so lets updated
// the original file, bloodrecord.txt, with the updated
// list of donors.
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b, sizeof(struct blood), 1, fp1))
{
fwrite(&b, sizeof(struct blood), 1, fp);
}
fclose(fp);
fclose(fp1);
printf("RECORD SUCCESSFULLY DELETED");
}
else
{
printf("\n\aRECORD DOES NOT EXIST.\n");
}
getchar();
getchar();
return found; // indicate if we found a match or not.
}
I reused most of your code, and added a second pass to handle the actual delete (first pass searches for matching records).
void delete(struct blood *b,int n)
{
const int MOBILE_SIZE = 16;
char name[50];
int phone = 0;
int found=0;
int c=0;
FILE *fp = fopen("bloodrecord.txt", "r");
FILE *fp1 = fopen("temp.txt", "w");
printf("\nEnter Name: ");
scanf("%s", name);
printf("---------------------------------------------\n");
while(fread(&b[i],sizeof(struct blood),1,fp))
{
if(strcmpi(b[i].name,name)==0)
{
c=c+1;
printf("\nName: %s\n",b[i].name);
printf("Age: %d\n", b[i].age);
printf("Mobile no.: %d\n", b[i].phone);
printf("Blood group: %s\n", b[i].bg );
printf("Weight: %d\n", b[i].weight);
printf("Sex: %s\n",b[i].sex);
printf("Address: %s\n",b[i].add);
printf("\n");
found = 1;
}
}
/* Finished the first pass. Now, start again */
rewind(fp)
if (c > 1) {
printf("There are multiple records for the name %s\n", name);
printf("\nEnter Mobile Number: ");
scanf("%d", &phone);
}
while(fread(&b[i],sizeof(struct blood),1,fp))
{
if((c == 1 && strcmpi(b[i].name,name)==0)
|| (c > 1 && strcmpi(b[i].name,name) == 0 && b[i].mobile == mobile))
continue; /* skip this record */
}
else
fwrite(&b[i],sizeof(struct blood),1,fp1);
}
fclose(fp);
fclose(fp1);
if (found==1)
{
fp1 = fopen("temp.txt", "r");
fp = fopen("bloodrecord.txt", "w");
while(fread(&b[i],sizeof(struct blood),1,fp1))
{
fwrite(&b[i],sizeof(struct blood),1,fp);
}
fclose(fp);
fclose(fp1);
}
else
{
printf("\n\aRECORD DOES NOT EXIST.\n");
}
printf("RECORD SUCCESSFULLY DELETED");
getchar();
getchar();
}
So I've been doing some coding for Homework and I found some problems with displaying, sorting, update, and even delete file. there are many codes that I found but none of them works, I can't even find the code for delete the file.. can you guys help me?
#include<stdio.h>
#include<stdlib.h>
char id[20], year[20], title[20], name[20];
void write(char id[], char title[], char name[], char year[])
{
FILE *fp;
fp = fopen("book.txt", "r");
if(fp == NULL)
{
fp = fopen("book.txt", "w");
fprintf(fp, "ID TITLE NAME YEAR\n");
fprintf(fp, "%s\t\t%s\t\t%s\t\t%s\t\t", id, title, name, year);
}
else
{
fp = fopen("book.txt.", "a");
fprintf(fp, "%s\t\t%s\t\t%s\t\t%s\t\t", id, title, name, year);
exit(2);
}
fclose(fp);
}
void displayfile()
{
FILE *fp;
fp = fopen("book.txt", "r");
if(fp == NULL)
{
printf("there is no data");
}
while(!feof(fp))
{
fscanf(fp, "%[^#]#%[^#]#%[^#]#%[^#]#%s", id, title, name, year);
printf("\n%s\t\t\n%s\t\t\n%s\t\t\n%s\t\t", id, title, name, year);
}
fclose(fp);
}
void updatefile()
{
FILE *fp;
int ch;
fp = fopen("book.txt", "r+");
if(fp == NULL)
{
fprintf(stderr, "there is no data");
exit(1);
}
while ((ch = fgetc(fp)) !=EOF)
{
if(ch == 'i')
{
fseek(fp, -1, SEEK_CUR);
fputc('a', fp);
fseek(fp, 0, SEEK_CUR);
}
}
fclose(fp);
}
void deletefile()
{
int apus;
FILE *fp;
fp = fopen("book.txt", "r");
}
int main() {
int option;
printf("please select one of this : \n");
printf("1. Input Book Record\n");
printf("2. Display Book Record\n");
printf("3. Update Book Record\n");
printf("4. Erase Book Record\n");
scanf("%d", &option);
switch(option)
{
case 1:
printf("Book ID?");
scanf("%s", id);
printf("Book title?");
scanf("%s", title);
printf("author name?");
scanf("%s", name);
printf("year published?");
scanf("%s", year);
write(id, title, name, year);
break;
case 2:
displayfile();
break;
case 3:
updatefile();
}
getchar();
return 0;
}
Looking at your code, you mean with "delete a file" to delete a record from the file. Since you use text files, this means:
open the input file book.txt for reading.
open a new file for writing with a temporary name, e.g. tmpbook.txt.
read the input file, writing each record that must not be deleted to the temporary file.
if you have read the record to be deleted, don't do anything ("skip it").
read all the remaining book records and write them to the temporary file.
close input and temporary file.
unlink book.txt.
rename tmpbook.txt to book.txt.
Now you are done.
The above procedure is for sequential files. Compare it with deleting a sentence from a text document. After the delete, all text moves up so the text reads contiguous again. Sentences do not have the same length.
For random access files (like databases), you can delete a record by giving it a marker that it has been deleted. In you program managing the file, you now simply do not show a record if the marker says it has been deleted, and if a new record is entered, you can re-use a deleted record. For this to work, all records must have the same size. You can use seek here to position the file pointer and you open the file for both reading and writing.
Add modified your code to make it works.
I embedded some comments to explain the changes.
I outlined the updatefile function it should be
easy for you to implement. If you still need help comment please.
#include<stdio.h>
#include<stdlib.h>
char id[20], year[20], title[20], name[20];
void writeTofile(char id[], char title[], char name[], char year[])
{
FILE *fp;
fp = fopen("book.txt", "a"); // if the file is not exist, it will create it.
// do not forget the \n not a new line
fprintf(fp, "%s\t%s\t%s\t%s\n", id, title, name, year);
fclose(fp);
exit(2);
}
void displayfile()
{
FILE *fp;
fp = fopen("book.txt", "r");
if(fp == NULL)
{
fprintf(stderr, "there is no data");
exit(1);
}
while(!feof(fp))
{
fscanf(fp, "%s %s %s %s", id, title, name, year);
printf("%s: %s\t%s\t%s\n", id, title, name, year);
}
fclose(fp);
}
void updatefile(char d, char n)
{
// open the book.txt for read
// open the temp.txt for write
// move all the char from the book.txt to temp.txt
// up to the location where you want to change
// Now add the new chars to the temp file
// continue copying
// close the book.txt
// open it again for write (to delete its content)
//copy temp to the book.txt
// doen
}
void deletefile()
{
int apus;
FILE *fp;
// if you want to delete the file use
// remove("book.txt"), BUT
// if you want to empty the file use
//(opening he file with white will delete its content )
fp = fopen("book.txt", "w");
}
int main() {
int option;
char d, n;
printf("please select one of this : \n");
printf("1. Input Book Record\n");
printf("2. Display Book Record\n");
printf("3. Update Book Record\n");
printf("4. Erase Book Record\n");
scanf("%d", &option);
switch(option)
{
case 1:
printf("Book ID?");
scanf("%s", id);
printf("Book title?");
scanf("%s", title);
printf("author name?");
scanf("%s", name);
printf("year published?");
scanf("%s", year);
writeTofile(id, title, name, year);
break;
case 2:
displayfile();
break;
case 3:
printf("Character to be replaced: ");
scanf("%c", &d);
printf("A new character: ");
scanf("%c", &n);
updatefile(d, n);
break;
case 4:
deletefile();
break;
}
getchar();
return 0;
}
My purpose is to create programme to manage records in files using c. the programme should be able to get info from console, write to a file and then read from it. Struct itself is working fine, but I'm not getting all the values i have written(see output)
and source code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct dob
{
int date;
int month;
int year;
};
struct person
{
int id;
char firstName[20];
char lastName[20];
struct dob date;
char email[20];
int phoneNo;
}new;
void readRecordsFromFile();
void readRecordsFromKeyboard();
int main(int argc, const char * argv[]) {
puts("Hello");
while (1) {
puts("Select option. \n 1. Read records from file. \n 2. Read records from keyboard \n Type any number to exit\n");
int i;
scanf("%d", &i);
switch (i) {
case 1:
readRecordsFromFile();
break;
case 2:
readRecordsFromKeyboard();
break;
default:
return 0;
break;
}
}
return 0;
}
void readRecordsFromFile(){
//struct person new;
char filename[100];
puts("Scpecify the file name to read data");
scanf("%s", filename);
struct person *new=malloc(sizeof(struct person));
FILE * file= fopen(filename, "rb");
if (file != NULL) {
fread(new, sizeof(struct person), 1, file);
fclose(file);
}
printf("\nID: %d\nName: %s\nSurname: %s\nDay of birth:%d\nMonth of birth:%d\nYear of birth:%d\nE-mail: %s\nPhone Number: %d\n",new->id,new->firstName,new->lastName,new->date.date,new->date.month,new->date.year,new->email,new->phoneNo);
}
void readRecordsFromKeyboard(){
struct person *new=malloc(sizeof(struct person));
puts("Enter the info about person");
puts("ID number");
scanf("%d", &new->id);
puts("First Name");
scanf("%19s", new->firstName);
puts("Last name");
scanf("%19s", new->lastName);
puts("Day, month and year of birth.(by numbers, every is new line)");
scanf("%d", &new->date.date);
scanf("%d", &new->date.month);
scanf("%d", &new->date.year);
puts("Email");
scanf("%19s", new->email);
puts("Phone number");
scanf("%d", &new->phoneNo);
puts("Specify the file you want to write yor data");
char filename[100];
scanf("%99s",filename);
FILE *inputf;
inputf = fopen(filename,"wb");
if (inputf == NULL){
printf("Can not open the file.\n");
exit(0);
}else{
if (fwrite(new, sizeof(new), 1, inputf) != 1)
{
fprintf(stderr, "Failed to write to %s\n", filename);
return;
}else{
puts("Data saved\n");
printf("\nID: %d\nName: %s\nSurname: %s\nDay of birth:%d\nMonth of birth:%d\nYear of birth:%d\nE-mail: %s\nPhone Number: %d\n",new->id,new->firstName,new->lastName,new->date.date,new->date.month,new->date.year,new->email,new->phoneNo);
}
}
fclose(inputf);
}
here is your problem
inputf = fopen(filename,"wb");
This command clears file, because it file is opened with "wb".
If you are going to write multiple record in that file in several runs, open it with "wb+". Then use fseek() to go to end of file. after that write your record with fwrite().
In addition for fwrite() you need to use sizeof strusture, not pointer.Means that you need something like this:
if (fwrite(new, sizeof(struct person), 1, inputf) != 1)
{
}
Please help me. This is my code so far. The delete record function is not working and can someone help the update record function with following conditions:
- Ask user to input player name.
- Ask user to input player score.
- Ask user to input player level.
- If the player name does not exist on the list, then show message “name of [player name] not found!”
Thanks a lot.
#include <stdio.h>
#include <string.h>
struct Player {
char name[50];
int score;
int level;
};
struct Player data[50];
FILE *ptr;
FILE *ptr2;
int fileSize()
{
int lSize;
int end;
ptr = fopen("text.txt", "r");
lSize = ftell (ptr);
fseek (ptr, 0, SEEK_END);
end = ftell (ptr);
fseek (ptr, lSize, SEEK_SET);
return end;
}
int getNoOfRecords()
{
return (fileSize()/(sizeof(struct Player)));
}
void deletePlayerRecord()
{
char name[50];
int counter=0, i=0;
ptr2 = fopen("text2.txt","a");
int records = getNoOfRecords();
ptr = fopen("text.txt","a+");
do {
printf("Input player name[1..10]: ");
scanf("%[^\n]s", name);
fflush(stdin);
} while (strlen(name)<1 || strlen(name)>10);
while(counter!=records)
{
fread(&data,sizeof(struct Player),1,ptr);
if(strcmp(data[i].name,name)==0)
{
}
else
{
fwrite(&data,sizeof(struct Player),1,ptr2);
}
counter++;
}
fclose(ptr);
fclose(ptr2);
remove("text.txt");
rename("text2.txt","text.txt");
printf("\n%s successfully deleted.\n\n", name);
printf("Press Enter to continue....\n\n");
getchar();
}
void updatePlayerRecord()
{
char name[50];
int counter=0, i=0;
int records = getNoOfRecords();
ptr = fopen("text.txt","a+");
do {
printf("Input player name[1..10]: ");
scanf("%[^\n]s", name);
fflush(stdin);
} while (strlen(name)<1 || strlen(name)>10);
if(counter!=records)
{
fread(&data,sizeof(struct Player),1,ptr);
if(strcmp(data[i].name,name)==0)
{
}
counter++;
}
printf("\nScore and Level successfully updated.\n\n");
printf("Press Enter to continue....\n\n");
getchar();
}
void addPlayerRecord(){
int i=0;
do {
printf("Input player name[1..10]: ");
scanf("%[^\n]s", data[i].name);
fflush(stdin);
} while (strlen(data[i].name)<1 || strlen(data[i].name)>10);
fflush(stdin);
getchar();
data[i].score=0;
data[i].level=0;
ptr = fopen("text.txt", "a");
printf("\n");
fprintf(ptr, "\r\n%s#%d#%d", data[i].name, data[i].score, data[i].level);
fclose(ptr);
printf("\nData successfully added.\n\n");
printf("Press Enter to continue....\n\n");
getchar();
}
void viewPlayerRecord(){
int i=0;
ptr = fopen("text.txt", "r");
printf("Player Name\t\t|Average Score\t|Number of Playing\n");
printf("=======================================================\n");
while(fscanf(ptr, "%[^#]#%d#%d\n", data[i].name, &data[i].score, &data[i].level)!=EOF)
{
printf("%s\t\t\t|%d\t\t\t\t|%d\n", data[i].name, data[i].score, data[i].level);
i++;
}
fclose(ptr);
}
int main() {
int choice;
do{
printf("Score Record Dota Player\n");
printf("========================\n");
printf("1. View Record\n");
printf("2. Update Player Record\n");
printf("3. Add New Player\n");
printf("4. Delete Player\n");
printf("5. Save and Exit\n\n");
do {
printf("Input your choice[1..5]: ");
scanf("%d", &choice);
fflush(stdin);
getchar();
} while (choice < 1 || choice > 5);
switch (choice) {
case 1:
viewPlayerRecord();
break;
case 2:
updatePlayerRecord();
break;
case 3:
addPlayerRecord();
break;
case 4:
deletePlayerRecord();
break;
}
} while(choice!=5);
return 0;
}
There are many issues with your code:
Every operation works on the database file. That may be a good design, but a more usual approach would be to load the database into memory on startup, i.e. to populate your data and then work on this. When exiting the program, you commit all changes to the database file. (Your option 5 is named "Save and exit", but is effectively a null operation. That name hints at the outlined approach.)
You should make up your mind whether your database is a binary file or a text file. You use fprintf and fscanf, which are used for text files, when you add and display records, but you use fwrite and fread, which are used for binary files, when you update and delete records. In my opinion, binary access is a bit easier, because you just have to store and retrieve chunks of a fixed size, namely sizeof(struct Player). Text files are more user-friendly, because they can be displayed and modified in a text editor, but they have to be parsed and require more advanced error handling.
Your fileSize() will only work with binary files, but at the moment you write only text files. It is usually better to use the return values of the file functions to determine whether reading or writig was successful.
When the database file doesn't exist, your view function will crash. Check for file existence and for the correct format.
At the moment, you use data only as scratch space. You osften access data[i], but i is zero throughout your code.
A corrected delete function that works is:
void deletePlayerRecord()
{
struct Player p;
char name[50];
int del = 0;
ptr2 = fopen("text2.txt", "w");
ptr = fopen("text.txt", "r");
do {
printf("Input player name[1..10]: ");
scanf("%[^\n]s", name);
fflush(stdin);
} while (strlen(name)<1 || strlen(name)>10);
while (fscanf(ptr, "%[^#]#%d#%d\n", p.name, &p.score, &p.level) == 3) {
if(strcmp(p.name, name) == 0) {
printf("\n%s successfully deleted.\n\n", name);
del++;
} else {
fprintf(ptr2, "%s#%d#%d\n", p.name, p.score, p.level);
}
}
fclose(ptr);
fclose(ptr2);
remove("text.txt");
rename("text2.txt", "text.txt");
printf("%d character(s) deleted\n\n", del);
}
This code still has many drawbacks:
The success of fopen is not checked.
The fscanf and fprintf formats have to be copied verbatim from the view and add record options. That's bad style. You should probably write readPlayer and writePlayer functions.
The same goes for the input code. Write front-end functions that do the error checking so that you don't have to repeat the whole code over and over again. This makes the code hard to read and also prone to errors.
I'm creating a simple C program - employee database... My data are stored in a .txt file, separated by commas and \n, so it looks like this:
data1,id1,name1
data2,id2,name2
What is the best way (in C, not C++) to load all data from the file and every value save as independent variable (e.g. p->data, p->id, p->name)?
This is the code I use to store data into variables (not into the file, variables just for the script):
void insert(emp *p,int n)
{
p=p+n;
printf("\nenter name of emplyee:");
_flushall();
gets(p->name);
printf("\nenter employee id:");
scanf("%d",&p->empid);
printf("\nenter salary of the emplyee:");
scanf("%d",&p->salary);
printf("\nenter phone no of the emplyee:");
flushall();
gets(p->ph);
}
And this script saves data to a file:
void sejv(emp *p,int n)
{
int i;
FILE *fptr;
fptr=fopen("ulozka.txt","w+");
if(fptr==NULL){
printf("Error opening file!");
getchar();
}
printf("Ukladani...");
for(i=0;i<n;i++)
{
fprintf(fptr,"%d,%s,%d,%s\n",p->empid,p->name,p->salary,p->ph);
p=p+1;
}
fclose(fptr);
exit(0);
}
All I need is to load the data to the main function so I can work with it.
EDIT:
I'm adding the rest of my code:
typedef struct employee
{
char name[20],ph[20];
int empid,salary;
}emp;
void main()
{
emp e;
emp *p;
int n=0,ch;
p=&e;
}
And "something" from the function I need to create...
void nacti(emp *p,int n)
{
int i;
FILE *fptr;
fptr=fopen("ulozka.txt","r");
if(fptr==NULL){
printf("Error opening file!");
getchar();
}
printf("Nacitani...");
//loading function
p=p+n;
fscanf(fptr,"%d,%[^\,],%d,%s", &p->empid, p->name, &p->salary,p->ph);
printf("%s", p->name);
}
I need a function that would read the data from the txt file by collumns and rows (a loop that would add the data from the first row to a p, then increase the value of p by 1, insert data from the second row and so on...)
Thank you for any advice...
Check the below code it can be done ad shown below:
struct data
{
int index;
int id;
char name[30];
};
int main ()
{
struct data p[3];
int i=0;
FILE *fp = fopen("input.txt","r+");
while(fscanf(fp,"%d,%d,%s",&p[i].index,&p[i].id,p[i].name) != EOF)
{
i++;
}
i=0;
while(i<3)
{
fprintf(fp,"%d %d %s\n",p[i].index,p[i].id,p[i].name);
i++;
}
fclose(fp);
}