I'm writing a code for a simple phone book. Everything works fine except that after successfully deleting an entry using my delete function my append function cant seem to write entries to the file anymore. unless I delete the database.data file that I'm using to store the entries.
NOTE:
the character array file="database.data"
delete function:
void deletee()
{
int tode,count;
char ch;
printc();
count=1;
FILE *filepointer,*filepointer2;
filepointer=fopen(file,"r+");
filepointer2=fopen("datatemp.data","w+");
if(filepointer==NULL)
{
printf("ERROR ERROR!");
}
printf("Enter line number of the line to be deleted: \n");
scanf("%d",&tode);
while (ch!=EOF)
{
ch=getc(filepointer);
if(ch=='\n')
{
count++;
}
if(count!=tode)
{
fprintf(filepointer2,"%c",ch);
}
}
fclose(filepointer);
fclose(filepointer2);
remove(file);
rename("datatemp.data",file);
printf("Content successfully deleted!!");
}
heres the function for append:
void append(struct entry *ptr)
{
FILE *filepointer;
filepointer=fopen(file,"a+");
fflush(stdin); //This block is asking for the inputs to be placed into the file
printf("Enter FName: ");
scanf("%s",&ptr->fn);
printf("\nEnter LName: ");
scanf("%s",&ptr->ln);
printf("\nEnter MName: ");
scanf("%s",&ptr->mn);
printf("\nEnter BD: ");
scanf("%s",&ptr->bd);
printf("\nEnter CNum: ");
scanf("%s",&ptr->cn);
if(filepointer==NULL)
{
printf("The file does not exist.\n");
return;
}
system("cls");
fprintf(filepointer,"%15s%15s%15s%9s%11s\n",ptr->fn,ptr->ln,ptr->mn,ptr->bd,ptr->cn);
fclose(filepointer);
printf("Entries successfully written!\n");
}
struct entry
{
char fn[15];
char ln[15];
char mn[15];
char bd[9];
char cn[11];
}p;
if you want more details please do tell me.
UPDATE-
I narrowed down the problem to the while loop in the delete function my append function seems to work after using delete if the contents in the while loop were written like this:
while (ch!=EOF)
{
ch=getc(filepointer);
if(count!=tode)
{
fprintf(filepointer2,"%c",ch);
if(ch=='\n')
{
count++;
}
}
}
But if the while loop were written in this way it would delete all the entries following the specified line. whereas in my previous code for the while loop in the deletee function it only deletes that specific line, but as stated the problem of the append function not being able to write to the file will persist until I delete the file "database.data" manually.
Solved the problem turns out that the append function was able to write entries into the file the only problem is my print function couldnt print out the new entries due to the delete function leaving garbage after being executed. revised the code so that no garbage would be written after deleting.
void deletee()
{
int tode,count;
char ch,sc;
printc();
count=1;
FILE *filepointer,*filepointer2;
filepointer=fopen(file,"r+");
filepointer2=fopen("datatemp.data","w+");
if(filepointer==NULL)
{
printf("ERROR ERROR!");
}
printf("Enter line number of the line to be deleted: \n");
scanf("%d",&tode);
while (ch!=EOF)
{
ch=getc(filepointer);
if(count!=tode)
{
if(ch==EOF)
{
break;
}
fprintf(filepointer2,"%c",ch);
}
if(ch=='\n')
{
count++;
}
}
fclose(filepointer);
fclose(filepointer2);
swap();
remove("datatemp.data");
printf("Content successfully deleted!!");
}
Related
Hi I have trying to merge two text files alternatively in a way that I get one line from first file and then I get second line from the next one, please help me, spent way too much time on this and still cannot get anything on the new file. Code is given below.
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *pointer1, *pointer2, *pointer3;
char source1[80],source2[80],target[80];
char ch1,ch2;
printf("Enter the source and source 2\n");
scanf("%s %s", source1,source2);
printf("Enter the destination\n");
scanf("%s",target);
pointer1 = fopen(source1,"r");
pointer2 = fopen(source2,"r");
pointer3 = fopen(target,"w");
if(pointer1 == NULL || pointer2==NULL || pointer3==NULL)
{
printf("Cannot open a file\n ");
exit(1);
}
while(1)
{
if(ch1!=EOF)
{
ch1 = fgetc(pointer1);
while(ch1!='\n')
{
if(ch1==EOF)
break;
fputc(ch1,pointer3);
ch1=fgetc(pointer1);
}
}
if(ch2!=EOF)
{
ch2=fgetc(pointer2);
while(ch2!='\n')
{
if(ch2==EOF)
break;
fputc(ch2,pointer3);
ch2=fgetc(pointer2);
}
}
if(ch1==EOF && ch2==EOF)
break;
}
printf("Merging completed successfully\n");
printf("Press any key to exit\n");
getch();
}
I have edited my code because of fear that someone from the same course as me would copy my code and hand it in. Thanks for the answer you have given me, its a great help.
My program should allow me to add the new item into the system along with its name, price and quantity.
But during execution, my code seems to damage the file. I have no idea what's wrong and would not like to write a more complicated code.
The program just skip the quantity and return to the menu. Not allowing me to input the quantity .
#include <stdlib.h>
#include <string,h>
struct Item//declaring a structure
{
char code[25];//variables inside a structure
char name[25];
double price;
int quantity;
};
int main (void)
{
struct Item item;
FILE *fgst;
printf("-------------------------------\n");
printf(" ADD PRODUCT\n");
printf("-------------------------------\n");
fgst = fopen("gst.txt", "r");
if(fgst==NULL)
{
printf("File cannot be found\n");
}
else //else statement
{
printf("Add Code:\n");
scanf("%s", item.code);
printf("name:\n");
scanf("%s", item.name);
printf("price:\n");
scanf("%.2f",&item.price);
printf("quantity:\n");
scanf("%d", &item.quantity);
fprintf(fgst,"%s;%s;%.2f;%d\n",item.code,item.name,item.price,item.quantity);
fclose(fgst);
}//end else statement
break;
}
The content of the one of the file is as follow:
AS520;Jelly tartar;5.35;42
From the man scanf:
The scanf() family of functions scans input according to format as described below. This format may contain conversion specifications; the results from such conversions, if any, are stored in the locations pointed to by the pointer arguments that follow format.
The following statements are wrong:
scanf("%.2f",product.price);
scanf("%d", product.quantity);
They should have had the following form:
scanf("%.2f",&(product.price));
scanf("%d", &(product.quantity));
Your program crashes because of these lines:
scanf("%.2f",product.price);
scanf("%d", product.quantity);
scanf expects a pointer but you provide a double and an integer. Change these lines to:
scanf("%.2f",&product.price);
scanf("%d", &product.quantity);
And it will not crash. Also, you are trying to update a file but you open it as read only:
fopen("gst.txt", "r");
If you want to write to the file, you should use:
fopen("gst.txt", "ra");
I've fixed your segmentation fault and tested your program. Your scanf usage was the source of the problem.
#include <stdlib.h>
#include <stdio.h>
struct Product//declaring a structure
{
char code[25];
//variables inside a structure
char name[25];
double price;
int quantity;
};
int main(void) {
struct Product product;
int add;
FILE *fptr;
FILE *nfptr;
printf("-------------------------------\n");
printf(" ADD ITEM\n");
printf("-------------------------------\n");
printf("1.GST Items\n");
printf("2.Non-GST Items\n");
scanf("%d", &add);
switch (add) //start of switch statement
{
case 1:
fptr = fopen("gst.txt", "wr"); //open file
if (fptr == NULL)//checking whether the file is empty or not
{
printf("File cannot be found\n");
}
else //else statement
{
printf("Add Item Code:\n");
scanf("%s", product.code);
printf("Item name:\n");
scanf("%s", product.name);
printf("Item price:\n");
scanf("%.2lf", &product.price);
printf("Item quantity:\n");
scanf("%d", &product.quantity);
fprintf(fptr, "%s;%s;%.2f;%d\n", product.code, product.name, product.price, product.quantity);
fclose(fptr);
}//end else statement
break;
case 2:
nfptr = fopen("ngst.txt", "r"); //open file
if (nfptr == NULL)//checking whether the file is empty or not
{
printf("File cannot be found\n");
}
else //else statement
{
printf("Add Item Code:\n");
scanf("%s", product.code);
printf("Item name:\n");
scanf("%s", product.name);
printf("Item price:\n");
scanf("%.2lf", &product.price);
printf("Item quantity:\n");
scanf("%d", &product.quantity);
fprintf(nfptr, "%s;%s;%.2f;%d\n", product.code, product.name, product.price, product.quantity);
fclose(nfptr);
}//end else statement
break;
}
}
The main problem with the code is that it opens the file in read mode, and then tries to write to it. To append data to a file, use append mode ("a").
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 am creating this change function. void cha(struct cont x);, It will ask for the lname then check if its in the file. After that, It will edit.Asks for the lname and fname again. It works but it writes at the bottom of the file.
struct cont
{
char lname[20];
char fname[20];
}s;
void cha(struct cont x)
{
FILE *fp;
char lname[20];
int flag=0;
fp=fopen("database.dat","a+");
if(fp==NULL)
{
printf("file error");
}
else
{
printf("\nenter lname: ");
gets(lname);
while(fscanf(fp,"%s %s",x.lname,x.fname)==2)
{
if(strcmp(lname,x.lname)==0)
{
printf("enter lname: ");
gets(x.lname);
printf("enter fname: ");
gets(x.fname);
fseek(fp,-sizeof(x),SEEK_CUR);
fprintf(fp,"%s %s\n",x.lname,x.fname);
flag=1;
break;
}
}
if(flag==1)
{
printf("success!");
}
else
{
printf("data not found.");
}
}
fclose(fp);
}
fp=fopen("database.dat","r");
You have opened the file in read mode and you are trying to write to the file
fprintf(fp,"%s %s\n",x.lname,x.fname);
Use a+ to open the file in append mode.
gets() is no more a standard and use fgets() which takes care of buffer overflow.
Man says:
a+
Open for reading and appending (writing at end of file). The file is
created if it does not exist. The initial file position for reading is
at the beginning of the file, but output is always appended to the end
of the file.
Just write it to another file
FILE *newFile = fopen("newDatabase.dat","w");
if(strcmp(lname,x.lname)==0)
{
//scan data to tmp var
fprintf(newFile ,"%s %s\n",x2.lname,x2.fname);
}
else
{
//write original var
fprintf(newFile ,"%s %s\n",x.lname,x.fname);
}
you can then change the name of the new file to overwrite the old one if its important
I am slowly learning C, but not very well. I have been reading over the countless topics and questions on reading and writing, but I have yet to be able to find anything that makes this all click for me.
I was given the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct YouTubeVideo {
char video_name[1024]; // YouTube video name
int ranking; // Number of viewer hits
char url[1024]; // YouTube URL
};
struct YouTubeVideo Collection[MAX];
int tail = 0;
//-- Forward Declaration --//
void printall();
void insertion();
void branching(char option);
void menu();
int main()
{
char ch;
// TODO: Add code to load save data from file
printf("\n\nWelcome to CSE240: YouTube Classic Hits\n");
do {
menu();
fflush(stdin); // Flush the standard input buffer
ch = tolower(getchar()); // read a char, convert to lower case
branching(ch);
} while (ch != 'q');
return 0;
}
void menu()
{
printf("\nMenu Options\n");
printf("------------------------------------------------------\n");
printf("i: Insert a new favorite\n");
printf("p: Review your list\n");
printf("q: Save and quit\n");
printf("\n\nPlease enter a choice (i, p, or q) ---> ");
}
void branching(char option)
{
switch(option)
{
case 'i':
insertion();
break;
case 'p':
printall();
break;
case 'q':
// TODO: Add code to save data into a file
break;
default:
printf("\nError: Invalid Input. Please try again...");
break;
}
}
void insertion()
{
if(tail < MAX)
{
printf("\nWhat is the name of the video? (No spaces characters allowed)\n");
scanf("%s", Collection[tail].video_name);
printf("\nHow many viewer hits does this video have?\n");
scanf("%d", &Collection[tail].ranking);
printf("\nPlease enter the URL: ");
scanf("%s", &Collection[tail].url);
tail++;
}
else
{
printf("\nERROR: Your collection is full. Cannot add new entries.\n");
}
}
void printall()
{
int i;
printf("\nCollections: \n");
for(i = 0; i < tail; i++)
{
printf("\nVideo Name: %s", Collection[i].video_name);
printf("\nRanking (Hits): %d", Collection[i].ranking);
printf("\nURL: %s", Collection[i].url);
printf("\n");
}
}
I am suppose to write the code that will store the collection into a file and the likewise right the code that will load the file and read from it.
Thanks to a fairly helpful TA I was able to formulate the following code for each
void store()
{
FILE * fileName;
fileName = fopen ( "Ranking.dbm" , "wb" );
fwrite ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
fclose (fileName);
}
and
void read()
{
FILE *fileName;
fileName = fopen("ranking.dbm", "rb");
if (fileName != NULL){
fread ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
}
else {
printf("ERROR");
}
}
I believe these each to function but the real problem is I don't think I quite understand how and I believe that since I dont even know how they function, I dont know how to use them in the code.
I added both methods to the given code and came up with this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 100
struct YouTubeVideo {
char video_name[1024]; // YouTube video name
int ranking; // Number of viewer hits
char url[1024]; // YouTube URL
};
struct YouTubeVideo Collection[MAX];
int tail = 0;
//-- Forward Declaration --//
void printall();
void insertion();
void branching(char option);
void menu();
void store();
void read();
int main()
{
char ch;
read();
printf("\n\nWelcome to CSE240: YouTube Classic Hits\n");
do {
menu();
fpurge(stdin); // Flush the standard input buffer
ch = tolower(getchar()); // read a char, convert to lower case
branching(ch);
} while (ch != 'q');
return 0;
}
void menu()
{
printf("\nMenu Options\n");
printf("------------------------------------------------------\n");
printf("i: Insert a new favorite\n");
printf("p: Review your list\n");
printf("q: Save and quit\n");
printf("\n\nPlease enter a choice (i, p, or q) ---> ");
}
void branching(char option)
{
switch(option)
{
case 'i':
insertion();
break;
case 'p':
printall();
break;
case 'q':
store();
break;
default:
printf("\nError: Invalid Input. Please try again...");
break;
}
}
void insertion()
{
if(tail < MAX)
{
printf("\nWhat is the name of the video? (No spaces characters allowed)\n");
scanf("%s", Collection[tail].video_name);
printf("\nHow many viewer hits does this video have?\n");
scanf("%d", &Collection[tail].ranking);
printf("\nPlease enter the URL: ");
scanf("%s", &Collection[tail].url);
tail++;
}
else
{
printf("\nERROR: Your collection is full. Cannot add new entries.\n");
}
}
void printall()
{
int i;
printf("\nCollections: \n");
for(i = 0; i < tail; i++)
{
printf("\nVideo Name: %s", Collection[i].video_name);
printf("\nRanking (Hits): %d", Collection[i].ranking);
printf("\nURL: %s", Collection[i].url);
printf("\n");
}
}
void store()
{
FILE * fileName;
fileName = fopen ( "Ranking.dbm" , "wb" );
if (fileName != NULL)
{
fwrite ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
fclose (fileName);
}
else {
perror("Following error occurred(): ");
}
}
void read()
{
FILE *fileName;
fileName = fopen("Ranking.dbm", "rb");
if (fileName != NULL)
{
fread ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
fclose(fileName);
}
else {
perror("Following error occurred with fopen(): ");
}
}
Now I am sure anyone who has read this has probably already face palmed themselves cause they see the problem, but I do not. The code does not create the file to write to and likewise it has nothing to read from so I cant even begin to see what is wrong with that.
Now I am not looking for a given answer, but I would really like to know what it is I am doing incorrectly, what concepts I appear to not understand, and how I can go about fixing these. I have done a few hours of research on this already and I realize it is elementary, but I really would like a hand in learning. Its frustrating spending hours on a topic that the professor said should only take a couple of hours to complete at most.
You really should check the return value of fopen() against NULL - if there is a problem opening the file, it will return NULL and set errno. This is probably a permissions mistake, and by checking the return value and printing the error if one is set, you'll get more information on what went wrong.
Minor: Make sure to check the return values for things like fopen, fread, fwrite etc. more often.
Mild: You've got a potential typo in the filename (some operating systems have case-sensitive file names)
Severe: read() doesn't set up a value for tail... :)
I believe you may have a problem with the read function, which does not call fclose on the file handle (by the way, calling it fileName is a little misleading).
Because you leave the file open, it's entirely likely that you won't be able to overwrite it when you eventually call store. You haven't output any error messages if the file cannot be opened in that function, so it's quite easy to slip under the radar... At least until you wonder why your file date doesn't change.
Otherwise the code looks okay. All it does is dump the entire contents of your array out of memory and read it back in again. What you'll probably want to do is also write out the value of tail, since it is keeping track of how many elements you are keeping. So with minimal code changes, do this:
fwrite ( &tail, sizeof(int), 1, fileName);
fwrite ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
And of course the corresponding calls to fread in your read method.
fread ( &tail, sizeof(int), 1, fileName);
fread ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
To reiterate: don't forget to close your file!!!!
fclose(fileName);