Update record file in file - c

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.

Related

How to delete a record when there's more than one record of the same name in C

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();
}

I can't get my code to break out of the switch statement

I can't get my delete record function to break out of the switch case or even give me an error when the record doesn't exist. Could someone please tell me why this is?
Any help is much appreciated!
I can't get my delete record function to break out of the switch case or even give me an error when the record doesn't exist. Could someone please tell me why this is?
Any help is much appreciated!
void delete_record();
void displayContent();
struct Update
{
char studentName[50];
char studentID [50];
char emailID[100];
char courseID[5];
char grade[50];
} update2;
int main ()
{
int num;
do
{
printf("1. Delete a record for the specific name\n");
printf("2. Display Content of File\n");
printf("6. Exit\n");
switch(num)
{
case 1:
printf("this is a test\n");
delete_record();
break;
//displayContent();
//printf("this is a test 2\n");
case 2:
printf("\n\nDiplaying Contents of File\n\n");
displayContent();
default:
printf("Give me a break!\n");
break;
}
scanf("%d", &num);
} while (num != 6);
return 0;
}
void delete_record()
{
FILE *fp;
FILE *fp_tmp;
fp = fopen ("BINARY_FILE.txt", "w");
char studentsID[20];
printf("enter studentID to delete:");
scanf("%s",studentsID);
printf("is this a test?\n");
while(fread(&update2,sizeof(update2),1,fp))
{
printf("this is another test\n");
if(strcmp(update2.studentID,studentsID) != 0)
{
//printf("testing\n");
fwrite(&update2,sizeof(update2),1,fp);
}
else
{
printf("No student with that student ID\n");
}
}
printf("more tests\n");
fclose(fp);
return;
}
void displayContent()
{
char c;
// Open file
FILE *fp;
fp = fopen ("BINARY_FILE.txt", "r");
if (fp == NULL)
{
printf("File Has No Content\n");
exit(0);
}
// Read contents from file
c = fgetc(fp);
while (c != EOF)
{
printf ("%c", c);
c = fgetc(fp);
}
fclose(fp);
//return 0;
}
When using scanf to read from the keyboard you must remember
that all characters that you enter are written to the in-buffer,
this means that if you type in
42ENTER
The ENTER will also be present in the in-buffer, so next time you call scanf ENTER will still be in the buffer and then scanf returns 0 since the format specificier "%d" doesn't match.
The easiest way to handle input from keyboard in C and to avoid the hassle of scanf in-buffer by using fgets() to read from the keyboard, then use sscanf() to cherry pick from the buffer:
// always check return value from all runtime functions when possible
char buffer[128];
if (fgets(buffer,sizeof(buffer), stdin) != NULL)
{
if (sscanf(buffer, "%d", &num) == 1)
{
}
else {...}
}
else {...}

How to pass a text file into an array in c?

Noob programmer here...so please bear with me. I'm trying to pass an existing text file into an array however once my main Menu loads the information that once existed in that file goes away, even if I don't make any changes. it is just not keeping the information. The Program is supposed to allow the user to either create a new file or update and/or load an existing file. Any ideas on how to fix this issue? Thank you all!
char fileName[20] = "";
void loadEmployee()
{
FILE* fPtr;
char singleLine[150];
if (strcmp(fileName, "") == 0)
{
printf("\nWhat's the name of the file? ");
scanf_s("%s", fileName, 20);
}
fopen_s(&fPtr, fileName, "r");
while (!feof(fPtr))
{
fgets(singleLine, 150, fPtr);
puts(singleLine);
}
fclose(fPtr);
}
void saveEmployee()
{
FILE* fPtr;
if (strcmp(fileName, "") == 0)
{
printf("\nWhat's the name of the file? ");
scanf_s("%s", fileName, 20);
}
fopen_s(&fPtr, fileName, "w");
for (int i = 0; i < numEmps; i++)
{
fprintf(fPtr, "%s %f %f\n", emps[i].emps.name,
emps[i].emps.rate, emps[i].emps.hours);
}
fclose(fPtr);
}
void loadMenu()
{
int i = 0;
printf("1. Load from a file \n");
printf("2. Keyboard \n");
scanf_s("%d", &choice);
switch (choice)
{
case 1: loadEmployee();
break;
default:
break;
}
do
{
printf("\nMAIN MENU\n");
printf("1.Add Employee\n");
printf("2.Edit Employee\n");
printf("3.Print Employee\n");
printf("4.Print ALL employees\n");
printf("5.Exit\n");
scanf_s("%d", &choice);
switch (choice)
{
case 1: NameInput();
break;
case 2: printf("Choose employee: \n");
for (int i = 0; i < numEmps; i++)
{
printf("%d. %s \n", i + 1,
emps[i].emps.name);
}
scanf_s("%d", &choice);
empUpdate(choice - 1);
break;
case 3: printf("Choose employee: \n\n");
for (int i = 0; i < numEmps; i++)
{
printf("%d) %s \n", i + 1,
emps[i].emps.name);
}
scanf_s("%d", &choice);
printf("%s \n", emps[choice -
1].emps.name);
printf("%.2f \n", emps[choice -
1].emps.hours);
printf("%.2f \n", emps[choice -
1].emps.rate);
break;
case 4: PayOutput();
break;
case 5: printf("Quitting program!");
saveEmployee();
return;
default: printf("Invalid choice try again \n\n");
break;
}
} while (choice != 5);
}
int main()
{
struct information empsi[20];
loadMenu();
}
Your function loadEmployee only writes to a char[] that is local to the function (which means it’s discarded at the end).
When the program exits, you « save » the employee by reopening your file in write mode, which clears it, and what follows probably doesn’t do much, so the file remains empty.
Try actually returning or storing the data from the file outside your function so it can be reused later.
As #hugo said, the program reads the file but doesn't store the contents. This means emps will be empty. When you quit you open the file for writing deleting its contents. Beause emps is empty, nothing is written.
This can be solved by reading similar to how you're writing. I don't know exactly what emps looks like, but something like this.
for( numEmps = 1; fgets(singleLine, 150, fPtr); numEmps++ ) {
// I'm assuming emps is preallocated.
struct Employee emp = emps[numEmps-1];
sscanf(singleLine, "%80s %f %f",
emp.emps.name,
&emp.emps.rate,
&emp.emps.hours
);
}
Notice rather than using feof I'm looking at the return value of fgets. As Edward Karak mentioned, when reading lines don't check for eof.
Other issues in the code...
You're not checking whether your files actually opened.
fopen_s(&fPtr, fileName, "r");
if( !fPtr ) {
perror(fileName);
exit(1);
}
The code uses a lot of global variables. This leads to hard to understand code as anything can change those globals at any time. Instead, take advantage of function arguments and return values. Then you can completely understand a function just by looking at it.
For example, loadEmployee should take the struct to populate and the filename to read from, then return how many it read. saveEmployee is similar.
int loadEmployee(struct Employee *emps, char *fileName) {
...
return numEmps;
}
void saveEmployee(struct Employee *emps, char *fileName) {
...
}
Neither should be in charge of asking the user for the filename. This should be handled by the caller. Functions should do one thing; it makes them simpler and more flexible.
We can move the logic to get the filename into a function. Rather than using a global, we use a static variable. This variable is still local to the function, but does not get reset. getFileName remembers the filename.
char *getFileName() {
static char fileName[80] = "";
if (strcmp(fileName, "") == 0)
{
printf("\nWhat's the name of the file? ");
scanf("%20s", fileName);
}
return fileName;
}
...
switch(choice) {
case 1:
numEmps = loadEmployee(emps, getFileName());
break;
...
case 5:
printf("Quitting program!");
saveEmployee(emps, getFileName());
return;
}
...
These are not the source of your problem, but they will help structure your code so it's easier to understand and debug.

How do I add information into the text file during execution? C

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").

Search a record in a file with C [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I'm exercising with C and file management, I'm able to open a file, write a record on the file, close the file, but I have problem to find an already written record. This is my exercise: (The search in case 2)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main(){
struct info{
char name[40];
char sur[40];
};
struct info rec;
FILE *f1, *f2;
int sel, ser, res;
char cmp[40];
int cont=0;
f1=fopen("lis.txt","a+");
do{
do{
printf("1> Add account\n");
printf("2> Search account\n");
printf("3> Modify account\n");
printf("4> Exit\n");
printf("Type your choice -> ");
scanf("%d", &sel);
if(sel<1 || sel>4){
printf("ERROR: The choice isn't allowed\n");
}
}while(sel<1 || sel>4);
getchar();
switch(sel){
case 1:
printf("Insert new account\n");
printf("Write name: ");
fgets(rec.name, sizeof(rec.name), stdin);
printf("Write surname: ");
fgets(rec.sur, sizeof(rec.sur), stdin);
fputs(rec.name,f1);
fputs(rec.sur,f1);
fprintf(f1,"\n");
printf("Account added!\n");
break;
case 2:
printf("Search account\n");
printf("Write surname to search: ");
fgets(cmp, sizeof(cmp), stdin);
while(!feof(f1)){
if(strcmp(cmp,rec.sur)==0){
printf("ENT\n");
}
}
break;
// case 3:
// printf("Modify account\n");
// //funzione ricerca qua
// printf("Account modificato correttamente!\n");
// break;
case 4:
printf("Closing...\n");
break;
default:
printf("ERROR!\n");
break;
}
}while(sel!=4);
}
The programme isn't finished, so there are plenty of unused things that I'll fix later.
It is tested on OpenVMS.
there is always problem on how to use feof(), so please avoid using it...
why not to use feof() for loop exit condition. please here is link.
here is link to a good tutorial, i have combined it with your code and it works like charm...please look into it.
Below is the modified code,
struct info
{
char name[40];
char sur[40];
};
int Search_in_File(char *fname, char *str) {
FILE *fp;
int line_num = 1;
int find_result = 0;
char temp[40];
if((fp = fopen(fname, "r")) == NULL) {
return(-1);
}
while(fgets(temp, 40, fp) != NULL) {
if((strstr(temp, str)) != NULL) {
printf("A match found on line: %d\n", line_num);
printf("\n%s\n", temp);
find_result++;
}
line_num++;
}
if(find_result == 0) {
printf("\nSorry, couldn't find a match.\n");
}
//Close the file if still open.
if(fp) {
fclose(fp);
}
return(0);
}
int main()
{
struct info rec;
FILE *f1; //*f2;
int sel;// ser, res;
char cmp[40];
char fname[10] = "lis.txt";
int err = -1;
// int cont=0;
do{
do{
printf("1> Add account\n");
printf("2> Search account\n");
printf("3> Modify account\n");
printf("4> Exit\n");
printf("Type your choice -> ");
scanf("%d", &sel);
if(sel<1 || sel>4){
printf("ERROR: The choice isn't allowed\n");
}
}while(sel<1 || sel>4);
getchar();
switch(sel){
case 1:
f1=fopen(fname ,"a+");
if (!f1)
{
printf("lis.txt, no such file exits\n");
return -1;
}
printf("Insert new account\n");
printf("Write name: ");
fgets(rec.name, sizeof(rec.name), stdin);
printf("Write surname: ");
fgets(rec.sur, sizeof(rec.sur), stdin);
fprintf(f1,"%s",rec.name);
fprintf(f1,"%s\n",rec.sur);
fflush(f1);
printf("Account added!\n");
fclose(f1);
break;
case 2:
printf("Search account\n");
printf("Write surname to search: ");
fgets(cmp, 40, stdin);
err = Search_in_File(fname, cmp);
if(err < 0)
{
return err;
}
break;
case 3:
printf("Modify account\n");
break;
case 4:
printf("Closing...\n");
break;
default:
printf("ERROR!\n");
break;
}
}while(sel!=4);
return 0;
}
There are so many things to look after.
1. Files are not closed properly.
You have opened the file at the beginning of the program. and have never closed.
Anything you write into a file does not immediately written actually, they are buffered.
You need to flush it or close the file. So, before you do any other operation on the file, be sure it is flushed.
2. Records are not read back from file.
You have not read back the records from file. You always searching the current values of rec structure. You need to read each record to the structure before comparing. Also, if you do not read the file, the file pointer never advances, and the control stays in the loop forever.
3. New lines are not handled.
You have additional new lines after each records. You need to handles those while reading back records from the file. gets consumes one newline at the end of the line. So you need to manually handle the additional \n.
Additionally, you need to break from the while loop if you find your record. There is no point staying there unless you expect duplicates.
The following has some modification over your code. This works for me. You may try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main(){
struct info{
char name[40];
char sur[40];
};
struct info rec;
FILE *f1, *f2;
int sel, ser, res;
char cmp[40];
char dummy;
int cont=0;
do{
do{
printf("1> Add account\n");
printf("2> Search account\n");
printf("3> Modify account\n");
printf("4> Exit\n");
printf("Type your choice -> ");
scanf("%d", &sel);
if(sel<1 || sel>4){
printf("ERROR: The choice isn't allowed\n");
}
}while(sel<1 || sel>4);
getchar();
switch(sel){
case 1:
printf("Insert new account\n");
printf("Write name: ");
fgets(rec.name, sizeof(rec.name), stdin);
printf("Write surname: ");
fgets(rec.sur, sizeof(rec.sur), stdin);
f1=fopen("lis.txt","a+"); //<- open file for writing
fputs(rec.name,f1);
fputs(rec.sur,f1);
fprintf(f1,"\n");
fclose(f1); // close the file. this will flush the buffer.
printf("Account added!\n");
break;
case 2:
printf("Search account\n");
printf("Write surname to search: ");
fgets(cmp, sizeof(cmp), stdin);
f1=fopen("lis.txt","r"); //<- open the file for reading
while(!feof(f1)){
fgets(rec.name,sizeof(rec.name),f1); //<- read both the data. this will update the file pointer.
fgets(rec.sur,sizeof(rec.sur),f1);
fscanf(f1,"%c",&dummy); //<- this handles the additional newline
if(strcmp(cmp,rec.sur)==0){
printf("RECORD FOUND::\nName:%sSurname:%s\n\n",rec.name,rec.sur);
break; //<- break if record is found
}
}
fclose(f1); //<- close the file after you are done.
break;
// case 3:
// printf("Modify account\n");
// //funzione ricerca qua
// printf("Account modificato correttamente!\n");
// break;
case 4:
printf("Closing...\n");
break;
default:
printf("ERROR!\n");
break;
}
}while(sel!=4);
}
NOTE: As we are using feof() to exit the loop, we have to read the EOF to fulfil the exit condition. Hence in this code the loop continues one more time after the last record where EOF is read from the file. This is not a problem unless you are trying to print all the records. In that case use a different exit condition.
Let me understand your question first,
you mean you can't find a record that is entered previously.
Lets say that the code at this part:
printf("Search account\n");
printf("Write surname to search: ");
fgets(cmp, sizeof(cmp), stdin);
while(!feof(f1)){
if(strcmp(cmp,rec.sur)==0){
printf("ENT\n");
}
}
break;
does the reading of the file, then....
if you put the code this way:
open the file in case 2 in read mode as a+ will not work if you try to read a file
f1 = fopen("lis.txt", "r");
if (!f1) {
printf("lis.txt, no such file exits\n");
return -1;
}
while (feof(f1)) {
fgets(str, len, f1);
if (strcmp(str, sur) == 0) {
/// Do what ever you want, printing the record e.t.c..
}
}
Hope this helps, :)
The problem begins with the format in which you are writing the file. You could either write the whole struct info for each record or write each field on a line. In the first case, the file would be called "binary"; the second case "text". It seems like you would prefer a text file format.
To write a field on a line, change fputs(rec.name,f1) to fprintf(f1,"%s\n",rec.name), similarly for the other field. Now, a record consists for a fixed number of lines in a specific sequence--specifically, a line for name and a line for sur. You can then read a record with two calls to fgets.
If I read the code correctly then you are trying to search for records after writing them to to file without closing the file. If you want to do this you need to call rewind or fseek to go to the beginning.
Keep in mind that you either need to store you file position before doing this (ftell) or to close and open in append more before adding more records.
As John points out above, reading might not work at all in +a mode either. Best you close the file after each case and open it in the correct mode.

Resources