I'm trying to create phone book which has five function in c. I have formed just first function which takes and saves in file people's knowledge. However, I cannot succeed the second function which search just a person's (Not all people) knowledge from file.
To run this function (""display() function"") I want to a name from user to search and to display that name's knowledge on the screen. I wrote something but it didn't work. The problem is display() function. How can I read just one line and print it on the screen? Thanks in advance.
#include <stdio.h>
#include <stdlib.h> // "stdlib" library contains of exit() and malloc function
#include <Windows.h> // "Windows" library contains of Sleep() function
#include <string.h> // "string" library contains of strcmp() function
struct personKnowledge
{
char number[16];
char name[16];
char surname[16];
};
void newRecord();
void display();
void deletE();
void add();
void update();
FILE *ptrFILE;
int main()
{
int choice;
printf("\n\t\t *-* Phone Book Program *-*");
do
{
printf("\n\n\t\t 1) New record"); // The options are being presented to user
printf("\n\n\t\t 2) Display person knowledge");
printf("\n\n\t\t 3) Delete someone");
printf("\n\n\t\t 4) Add new person");
printf("\n\n\t\t 5) Update person knowledge");
printf("\n\n\t\t 6) Exit");
printf("\n\n\nEnter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
{
newRecord();
break;
}
case 2:
{
display();
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6:
{
printf("\nWorking has been completed.\n");
exit(0);
break;
}
default:
{
printf("\nWrong entry! The program has been terminated.\n");
}
}
} while (choice >=1 && choice <=6 );
return 0;
}
void newRecord()
{
system("cls"); // Screen is being cleaned
if ((ptrFILE = fopen("Phone Book.txt", "w")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
struct personKnowledge *p; // p means person
p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated
fflush(stdin);
printf("\n\nDetermine person name: "); // User is entering the person's knowledge and they are being saved in file
gets(p->name);
printf("Determine %s's surname: ", p->name);
gets(p->surname);
printf("Determine %s's number: ", p->name);
gets(p->number);
fprintf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n");
fprintf(ptrFILE, "--------\t\t ----------------\t\t\t---------------------\n");
fprintf(ptrFILE, "\n%s%33s%38s\n", p->name, p->surname, p->number);
fclose(ptrFILE);
free(p);
printf("Please wait, information is saving to file..\n");
Sleep(1000);
printf("*-* Saving operation has been completed. *-*");
}
fclose(ptrFILE);
}
void display()
{
struct personKnowledge *s; // s means searching
char name[16];
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
fseek(ptrFILE, 0L, SEEK_SET);
printf("Express name which you search: ");
gets(s->name);
while (!feof == NULL)
{
fscanf(ptrFILE,"%s", &name);
if (strcmp(s->name, name) == 0)
{
printf("qawsdsdf");
}
}
}
fclose(ptrFILE);
}
In answer to one of your questions, I recommend rewriting this loop in display()
while (!feof == NULL) // wrong way to use feof
{
fscanf(ptrFILE,"%s", &name); // might overflow the string space
if (s->name == name) // wrong way to compare strings
{
printf("qawsdsdf"); // missing newline?
}
}
with this
while (fgets(name, sizeof(name), ptrFILE) != NULL) // safer way to read to a small buffer
{
name [ strcspn(name, "\r\n") ] = 0; // remove trailing newline etc
if (strcmp(s->name, name) == 0) // compare the strings
{
printf("qawsdsdf\n"); // added newline
}
}
EDIT in any case your posted code does not even compile properly:
while (!feof == NULL)
is rubbish, it should have been
while (!feof(ptrFILE))
although as I said is not the way to use feof anyway. This would not have happened if you had compiler warnings enabled and dealt with them.
I think these minor changes will solve your problem
Allocate memory for storing personKnowledge s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
Make file pointer reach the starting location of data. A simple trick has been used to achieve this fscanf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n");
fscanf(ptrFILE, "--------\t\t ----------------\t\t\t---------------------\n");
Make change in while loop.while (!feof(ptrFILE))
Scanning one row of data.fscanf(ptrFILE, "\n%s%33s%38s\n", s->name, s->surname, s->number)
Make change in string comparison.if (strcmp(name,s->name) == 0)
The modified display function
void display(){
struct personKnowledge *s;
s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated for s
fflush(stdin);
char name[16];
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
fseek(ptrFILE, 0L, SEEK_SET);
printf("Express name which you search: ");
scanf("%s",name); //the name you want to retrieve
fscanf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n");
fscanf(ptrFILE, "--------\t\t ----------------\t\t\t---------------------\n"); //when we read the file for first time we need to start from the first location of person data, this is a trick to make ptrFILE reach there
fflush(stdin);
while (!feof(ptrFILE))
{
fscanf(ptrFILE, "\n%s%33s%38s\n", s->name, s->surname, s->number);//same format as fprintf used in newRecord
if (strcmp(name,s->name) == 0) //comparison
{
printf("qawsdsdf");
}
}}fclose(ptrFILE);}
My solution was to change how the file is formatted
fprintf(ptrFILE, "\n%s%33s%38s", p->name, p->surname, p->number);
Because if you're using a program to retrieve information, there's no need to fill it with a bunch of junk headers every time you write to it.
I then edited the display function to be able to retrieve said information.
void display()
{
struct personKnowledge s; // s means searching
char name[16];
char sname[16];
char number[16];
char surname[16];
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
printf("Express name which you search: ");
scanf("%s", &sname);
do
{
fscanf(ptrFILE,"%s%33s%38s", &name, &surname, &number);
if (strcmp(sname, name) == 0)
{
printf("%s %s %s", name, surname, number);
}
}
while (strcmp(sname, name) != 0);
}
}
P.S. I'm still new to c myself and I don't think I could give you a good explanation as to why my code works and yours doesn't. But I can say that those headers you were writing to the file every time was a major part of the problem when I was troubleshooting your code.
Related
I'm trying to write a simple phone book program. I have completed the first function and according to I observe it works without error. However, in second function (which is ""display()"") I can't show to user after I enter person knowledge. I'm working with binary mode. What the problem is in second function I couldn't understand. If you examine and help I'll be satisfied. Thanks in advance.
#include <stdio.h>
#include <stdlib.h> // "stdlib" library contains of exit() function
#include <malloc.h> // "malloc" library contains of malloc() function
#include <Windows.h> // "Windows" library contains of Sleep() function which waits the system as you want
#include <io.h> // "io" library contains of filelength() function
struct personKnowledge
{
char name[32];
char surname[32];
char number[32];
};
FILE *ptrFILE,*ptrFILE1;
long int recordLength,totalRecordLength,location;
static int counter = 0;
int number,totalRecordNumber;
void newRecord();
void display();
void deletE();
void add();
void update();
int main()
{
int choice;
do
{
printf("\n\t\t --- Phone Book Program ---");
printf("\n\n\t\t 1) New record"); // The options are being presented to user
printf("\n\n\t\t 2) Display person knowledge");
printf("\n\n\t\t 3) Delete someone");
printf("\n\n\t\t 5) Update person knowledge");
printf("\n\n\t\t 6) Exit");
printf("\n\n\nEnter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
{
newRecord();
break;
}
case 2:
{
display();
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6:
{
printf("\nWorking has been completed.\n");
return 0;
}
default:
{
printf("\nWrong entry! The program has been terminated.\n");
break;
}
}
} while (choice >= 1 && choice <= 6);
return 0;
}
void newRecord()
{
if ((ptrFILE = fopen("Phone Book.dat", "wb")) == NULL)
{
printf("The file couldn't open\n");
exit(0);
}
system("cls"); // Screen is being cleaned
struct personKnowledge *p; // p means person
p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated
fflush(stdin);
recordLength = sizeof(p); // size of p
printf("|| For the %d. person ||\n", counter+1);
printf("\n\Express person name: "); // User is entering the person's knowledge and they are being saved in file
gets(p->name);
printf("Express %s's surname: ", p->name);
gets(p->surname);
printf("Express %s's number: ", p->name);
gets(p->number);
fwrite(&(*p), recordLength, 1, ptrFILE);
printf("\nPlease wait, information is saving to file..\n");
Sleep(750);
printf("*-* Saving operation has been completed succesfully. *-*\n");
free(p);
counter++;
fclose(ptrFILE);
}
void display()
{
if ((ptrFILE = fopen("Phone Book.dat", "rb")) == NULL)
{
printf("The file couldn't open\n");
exit(0);
}
system("cls"); // Screen is being cleaned
struct personKnowledge *s; // s means searching
s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
fflush(stdin);
recordLength = sizeof(s);
totalRecordLength = filelength(fileno(ptrFILE));
totalRecordNumber = totalRecordLength / recordLength;
printf("\n\nExpress person record number which you search: ");
scanf("%d", &number);
location = (number - 1)*recordLength;
fseek(ptrFILE, location, SEEK_SET);
fread(&(*s), recordLength, 1, ptrFILE);
printf("\n*-* Person knowledge which you search *-*\n");
Sleep(750);
printf("Name: %s\n", s->name);
printf("Surname: %s\n", s->surname);
printf("Number: %s\n", s->number);
free(s);
fclose(ptrFILE);
}
recordLength = sizeof(p);
is wrong, this is the size of the pointer which is normally 4 on a 32 bit system and 8 on a 64 bit syste.
you need
recordLength = sizeof(*p);
or
sizeof(struct personKnowledge);
which gives you the size of the structure pointed by p.
I'm trying to write phone book program.I completed the first function(which saves knowledge). Program is running. However, after I enter the person's knowledge from keyboard and close the program it shows me just the last person's knowledge in file. I am using the program w mode, I tried w+ mode, too. But the problem still didn't change. For example as I use the first function I enter three people's knowledge but it shows me just one. How can I solve this ?
#include <stdio.h>
#include <stdlib.h> // "stdlib" library contains of exit() and malloc function
#include <Windows.h> // "Windows" library contains of Sleep() function which waits the system as you want
struct personKnowledge
{
char number[16];
char name[16];
char surname[16];
};
void newRecord();
void display();
void deletE();
void add();
void update();
FILE *ptrFILE;
int main()
{
int choice;
do
{
printf("\n\t\t *-* Phone Book Program *-*");
printf("\n\n\t\t 1) New record"); // The options are being presented to user
printf("\n\n\t\t 2) Display person knowledge");
printf("\n\n\t\t 3) Delete someone");
printf("\n\n\t\t 4) Add new person");
printf("\n\n\t\t 5) Update person knowledge");
printf("\n\n\t\t 6) Exit");
printf("\n\n\nEnter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
{
newRecord();
break;
}
case 2:
{
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6:
{
printf("\nWorking has been completed.\n");
exit(EXIT_SUCCESS);
break;
}
default:
{
printf("\nWrong entry! The program has been terminated.\n");
break;
}
}
} while (choice >= 1 && choice <= 6);
return 0;
}
void newRecord()
{
system("cls"); // Screen is being cleaned
if ((ptrFILE = fopen("Phone Book.txt", "w")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
struct personKnowledge *p; // p means person
p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated
fflush(stdin);
printf("\n\nDetermine person name: "); // User is entering the person's knowledge and they are being saved in file
gets(p->name);
printf("Determine %s's surname: ", p->name);
gets(p->surname);
printf("Determine %s's number: ", p->name);
gets(p->number);
fprintf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\tNumber\n");
fprintf(ptrFILE, "--------\t\t ----------------\t\t------------------------\n");
fprintf(ptrFILE, "\n%s%33s%38s\n", p->name, p->surname, p->number);
free(p);
printf("Please wait, information is saving to file..\n");
Sleep(750);
printf("*-* Saving operation has been completed. *-*");
}
fclose(ptrFILE);
}
You are using write mode to write output to an already existing file. To preserve it's contents, use append modes like a or a+. For example
FILE * ptrFILE = fopen("Phone Book.txt", "a");
The description of other modes (may not be compatible with all platforms):
r or rb - Open file for reading.
w or wb - Truncate to zero length or create file for writing.
a or ab - Append; open or create file for writing at end-of-file.
r+ or rb+ or r+b - Open file for update (reading and writing).
w+ or wb+ or w+b - Truncate to zero length or create file for update.
a+ or ab+ or a+b - Append; open or create file for update, writing at end-of-file.
You should open it in append mode. Try this: if ((ptrFILE = fopen("Phone Book.txt", "a")) == NULL) Append mode will add contents to the end of your existing file contents.
If you open in write mode ("w" or "w+"), the last text is saved in file, but if you will open in append mode ("a" or "a+"), your file will include all of your writing.
Well in above mentioned programs-
Fisrt Program always enters the last record you enetres as you opened file in "w" mode and you call function void newRecord() again to enter another record thus closing file then again opening it. As already contains data you want next record after it but as file is opened in "w" mode it discards already present data in file and the file is treated as a new empty file.
In second program you mentioned in your answer is just main function thus not causing opening and closing of file again and again. That is why it normally saves your data.
Use "a" or "a+" mode to make your first program work normally.
No need a or a+ mode. I insist :) Here are new codes. The problem has been solved.
#include <stdio.h>
#include <stdlib.h> // "stdlib" library contains of exit() and malloc function
#include <Windows.h> // "Windows" library contains of Sleep() function which waits the system as you want
struct personKnowledge
{
char number[16];
char name[16];
char surname[16];
};
void newRecord(FILE *);///
void display();
void deletE();
void add();
void update();
FILE *ptrFILE;
int main()
{
int choice;
if ((ptrFILE = fopen("Phone Book.txt", "w+")) == NULL)
{
printf("The file couldn't open\n");
}
do
{
printf("\n\t\t *-* Phone Book Program *-*");
printf("\n\n\t\t 1) New record"); // The options are being presented to user
printf("\n\n\t\t 2) Display person knowledge");
printf("\n\n\t\t 3) Delete someone");
printf("\n\n\t\t 4) Add new person");
printf("\n\n\t\t 5) Update person knowledge");
printf("\n\n\t\t 6) Exit");
printf("\n\n\nEnter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
{
newRecord(ptrFILE);
break;
}
case 2:
{
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6:
{
printf("\nWorking has been completed.\n");
exit(EXIT_SUCCESS);
break;
}
default:
{
printf("\nWrong entry! The program has been terminated.\n");
}
}
} while (choice >= 1 && choice <= 6);
fclose(ptrFILE);
return 0;
}
void newRecord(FILE *ptrFILE)
{
static int counter = 0;
system("cls"); // Screen is being cleaned
struct personKnowledge *p; // p means person
p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated
fflush(stdin);
printf("\n\nDetermine person name: "); // User is entering the person's knowledge and they are being saved in file
gets(p->name);
printf("Determine %s's surname: ", p->name);
gets(p->surname);
printf("Determine %s's number: ", p->name);
gets(p->number);
if (counter == 0)
{
fprintf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\tNumber\n");
fprintf(ptrFILE, "--------\t\t ----------------\t\t------------------------\n");
}
fprintf(ptrFILE, "\n%33s%33s%38s\n", p->name, p->surname, p->number);
printf("Please wait, information is saving to file..\n");
Sleep(750);
printf("*-* Saving operation has been completed. *-*");
counter++;
free(p);
}
I am writing a phone book program. I completed first function.
However, in second function (("" display() function "")) there is something wrong which is I couldn't find.
In display() function, I'm taking another name which is searched by user and comparing it with names into file to show that person's knowledge (Just one person) on the screen. But it doesn't work. How can I solve this problem?
#include <stdio.h>
#include <stdlib.h> // "stdlib" library contains of exit() and malloc function
#include <Windows.h> // "Windows" library contains of Sleep() function which waits the system as you want
#include <string.h> // "string" library contains of strcmp() function which compares string statements
struct personKnowledge
{
char number[16];
char name[16];
char surname[16];
char sName[16];
};
void newRecord(FILE *);
void display(FILE *);
void deletE();
void add();
void update();
FILE *ptrFILE;
int main()
{
int choice;
if ((ptrFILE = fopen("Phone Book.txt", "w+")) == NULL)
{
printf("The file couldn't open\n");
}
do
{
printf("\n\t\t --- Phone Book Program ---");
printf("\n\n\t\t 1) New record"); // The options are being presented to user
printf("\n\n\t\t 2) Display person knowledge");
printf("\n\n\t\t 3) Delete someone");
printf("\n\n\t\t 4) Add new person");
printf("\n\n\t\t 5) Update person knowledge");
printf("\n\n\t\t 6) Exit");
printf("\n\n\nEnter your choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
{
newRecord(ptrFILE);
break;
}
case 2:
{
display(ptrFILE);
break;
}
case 3:
{
break;
}
case 4:
{
break;
}
case 5:
{
break;
}
case 6:
{
printf("\nWorking has been completed.\n");
exit(EXIT_SUCCESS);
break;
}
default:
{
printf("\nWrong entry! The program has been terminated.\n");
}
}
} while (choice >= 1 && choice <= 6);
fclose(ptrFILE);
return 0;
}
void newRecord(FILE *ptrFILE)
{
static int counter = 0;
system("cls"); // Screen is being cleaned
struct personKnowledge *p; // p means person
p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge)); // Memory is being allocated
fflush(stdin);
printf("\n\nDetermine person name: "); // User is entering the person's knowledge and they are being saved in file
gets(p->name);
printf("Determine %s's surname: ", p->name);
gets(p->surname);
printf("Determine %s's number: ", p->name);
gets(p->number);
if (counter == 0)
{
fprintf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\tNumber\n");
fprintf(ptrFILE, "--------\t\t ----------------\t\t------------------------\n");
}
fprintf(ptrFILE, "\n%-33s%-33s%-38s\n", p->name, p->surname, p->number);
printf("Please wait, information is saving to file..\n");
Sleep(750);
printf("*-* Saving operation has been completed. *-*\n");
counter++;
free(p);
}
void display(FILE *ptrFILE)
{
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
system("cls"); // Screen is being cleaned
struct personKnowledge *s; // s means searching
s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
fseek(ptrFILE, 0L, SEEK_SET);
fflush(stdin);
printf("\n\nExpress name which you search: ");
gets(s->sName);
while (!feof(ptrFILE))
{
fscanf(ptrFILE, "\n%-33s%-33s%-38s\n", &s->name, &s->surname, &s->number);
if (strcmp(s->name, s->sName) == 0)
{
printf("*-* Person knowledge who is you search *-*\n");
Sleep(750);
printf("\n\nName: %s\nSurname: %s\nNumber: %s\n", s->name, s->surname, s->number);
}
}
free(s);
}
}
The MSVC documentation of fopen says about mode: "w" Opens an empty file for both reading and writing. If the file exists, its contents are destroyed.
Since the first file open in main is
if ((ptrFILE = fopen("Phone Book.txt", "w+")) == NULL)
you destroy anything you already have.
To read the content, use mode "r" to open the file, read the content, then close it.
To add new content, either re-open with mode "w" and write the whole content, or open in append mode "a" and just write the new records(s).
Or you can open in mode "r+" for reading and writing, but before writing you need to fseek the end of the file.
In int main() you opened file with "w+" mode so everything is discarded in file when it is called.
Also in function void display(FILE *ptrFILE) you have not closed the text file.And you have used feof() inside while loop which may create problem .
Please see following link why you should not use while(!feof())-Why is “while ( !feof (file) )” always wrong?
void display(FILE *ptrFILE)
{
fclose(ptrFILE);//!! flush out
if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
{
printf("The file couldn't open\n");
}
else
{
char buff[128];//!!for fgets
system("cls"); // Screen is being cleaned
struct personKnowledge *s; // s means searching
s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
//fseek(ptrFILE, 0L, SEEK_SET);//!!no need
fflush(stdin);
printf("\n\nExpress name which you search: ");
gets(s->sName);
while (fgets(buff, sizeof buff, ptrFILE))//!!
{
sscanf(buff, "%15s%15s%15s\n", s->name, s->surname, s->number);//!!
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.
This is my code for a project I'm working on, my aim is to create a database where i can add edit and delete records. The program is compiling but very slowly and often crashes. I am a mere beginner and I cant figure out why this is happening. Maybe somebody can help me improve the code or point me in the right direction?
enter code here
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void clearInput(void);
void listAll (void);
void deleteAccount(void);
void addNewAccount(void);
void modifyAccount(void);
int prompt(void);
struct account{
int number;
char lastname[15];
char firstname[15];
float balance;
struct account*next;
};
struct account *firsta, *currenta, *newa;
int anum = 0;
int main()
{
FILE *datafile;
char *filename="studentdatabase.txt";
char ch;
firsta=NULL;
datafile=fopen(filename, "r");
if (datafile) /*assume doesnt exist otherwise*/
{
firsta=(struct account*)malloc(sizeof(struct account));
currenta=firsta;
while (1)
{
newa=(struct account*)malloc(sizeof(struct account));
fread(currenta, sizeof(struct account),1,datafile);
if (currenta->next==NULL)
break;
currenta->next=newa;
}
fclose(datafile);
anum=currenta->number;
}
do
{
clearInput();
puts("\nA - Add a new account");
puts("D - Delete account");
puts("L - List all accounts");
puts("M - Modify account");
puts("Q - Quit this program\n");
printf("\tYour Choice:");
ch=getchar();
ch=toupper(ch);
switch(ch)
{
case 'A':
puts("Add new account\n");
clearInput();
addNewAccount();
break;
case 'D':
puts("Delete account\n");
deleteAccount();
break;
case 'L':
puts("List all accounts\n");
listAll();
break;
case 'M':
puts("Modify an account\n");
modifyAccount();
break;
case 'Q':
puts ("Quit\n");
default:
break;
}
}
while(ch!='Q');
/*Save the records to disc*/
currenta=firsta;
if(currenta==NULL)
return(0); /*No data to write - End of Program*/
datafile=fopen(filename,"w");
if (datafile=NULL)
{
printf("Error writing to %s\n", filename);
return(1);
}
/*write each record to disc*/
while(currenta!=NULL)
{
fwrite(currenta, sizeof(struct account),1,datafile);
currenta=currenta->next;
}
fclose(datafile);
return(0);
}
/*This function clears any text from the input stream*/
void clearInput(void)
{
fflush(stdin);
}
void addNewAccount(void)
{
newa=(struct account*)malloc(sizeof(struct account));
/*Check to see if this is the first record, if so then
itialize all the pointers to this, first ftrusture in
the database*/
if(firsta==NULL)
firsta=currenta=newa;
/*Otherwise you must find the end of the structure list
(easily spotted by the NULL pointer) and add on the new
structure you just allocated memory for*/
else
{
currenta=firsta; /*makes the first current*/
/*loop throught all records*/
while(currenta->next!=NULL)
currenta=currenta->next;
/*last record found*/
currenta->next=newa; /*save the address of new*/
currenta=newa; /*makes current new*/
}
/*now you just fill in the new structure*/
anum++;
printf("%27s:%5i\n","Account number", anum);
currenta->number=anum;
printf("%27s:","Enter customer's lastname");
gets(currenta->lastname);
printf("%27s:","Enter firstname");
gets(currenta->firstname);
printf("%27f:€","Enter account balance");
scanf("%f", ¤ta->balance);
/*Finally cap the new record with a NULL pointer so
that you know its the last record*/
currenta->next=NULL;
}
void listAll(void)
{
if (firsta==NULL)
puts("There are no records to print out");
else
{
printf("%6s %-15s %-15s €%8.2f\n",
currenta->number,
currenta->lastname,
currenta->firstname,
currenta->balance);
}
while ((currenta=currenta->next) !=NULL);
}
void deleteAccount(void)
{
int record;
struct account *previousa;
if(firsta==NULL)
{
puts("There are no records to delete");
return;
}
listAll();
/*Shows all record first*/
printf("Enter account number to delete: ");
scanf("%d",&record);
currenta=firsta;
while(currenta!=NULL)
{
{
if(currenta->number==record)
{
if(currenta==firsta) /*special condition*/
firsta=currenta->next;
else
previousa->next=currenta->next;
free(currenta);
printf("Account %d deleted! \n", -record);
return;
}
previousa=currenta;
currenta=currenta->next;
}
}
printf("Account %d was not found!\n", record);
puts("Nothing deleted.");
}
void modifyAccount(void)
{
int record;
if (firsta==NULL)
{
puts("There are no records to modify!");
return;
}
listAll(); /*Show all records first*/
printf("Enter account number to modify or change: ");
scanf("%d",&record);
currenta=firsta;
while (currenta!=NULL)
{
if(currenta->number==record)
{
printf("Account €%d:\n", currenta->number);
printf("Last name: %s\n", currenta->lastname);
if (prompt())
gets (currenta->lastname);
printf("firstname %s \n", currenta->firstname);
if (prompt())
gets(currenta->firstname);
printf("Balance %8.2f\n", currenta->balance);
if (prompt())
scanf("%f", ¤ta->balance);
return;
}
else
{
currenta=currenta->next;
}
}
printf("Account %d was not found!\n", record);
}
int prompt(void)
{
char ch;
clearInput();
printf("Update?");
ch=getchar();
ch=toupper(ch);
clearInput();
if(ch=='Y')
{
printf("Enter new. ");
return(1);
}
else return(0);
}
Your input loop in the start looks a bit odd to me.
while (1)
{
newa=(struct account*)malloc(sizeof(struct account));
fread(currenta, sizeof(struct account),1,datafile);
if (currenta->next==NULL)
break;
currenta->next=newa;
}
I understand that you are relying on the fact that when you wrote out the list the last structure written should have had the 'next' field set to NULL as your end marker, but I would suggest you might want find a cleaner way to check for end. This will also have a small memory leak since you allocate newa but then break on the last read, so that last newa is never used.
Also, the load routine results in the first record in the list being an empty record because you allocate firsta, set currenta to it, then allocate newa for the first read and set it to the next of the empty currenta.
After loading, though you will only ever have 1 record. Notice that you are not reading into newa you read into currenta
fread(currenta, sizeof(struct account),1,datafile);
Your attempt to save the data also has an issue, you have one of the classic typo errors:
datafile=fopen(filename,"w");
if (datafile=NULL)
^^^
you are reassigning NULL to the datafile variable, you need == here.
You appear to assume through out the code that currenta, which is global, is in a known state. For example, in the listAll function, your code is not setting currenta before printing out a record. Note also listAll is not looping and printing all records, you print only whatever currentA is then move that variable to being NULL.
I would suggest you keep only firsta as a global to locate the head of the list, but everywhere else you use local variables and set them up correctly.
As previously mentiond, your printf statements need to match their data types. That can cause failures.
One problem is in the printf:
printf("%6s %-15s %-15s €%8.2f\n",
currenta->number,...
Here you are printing an integer currenta->number using %s format specifier, use %d instead.
Another problem is when you are trying to print the list:
printf(...);
while ((currenta=currenta->next) !=NULL);
This is not how you print the list. You need to have a printf as the body of the while loop:
while (currenta != NULL) {
printf(...);
currenta = currenta->next;
}