I wrote a program that collects user data and saves it to a file. At the moment when he wants to view the file, the program loops and shows only the first record. I do not know what this error is caused.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
FILE *fptr;
struct notification {
char name[50];
char lastname[50];
char price[10];
char descreption[100];
}notification;
void insertRecord()
{
fptr=fopen("G:\\file.txt","a+");
fflush(stdin);
printf("Podaj imie: ");
gets(notification.name);
printf("Podaj nazwisko: ");
gets(notification.lastname);
printf("Podej cene: ");
gets(notification.price);
printf("Podaj opis usterki: ");
gets(notification.descreption);
strcat(notification.descreption,"\n");
if(fwrite(¬ification,sizeof(notification),1,fptr) != 1)
{
perror("Blad: ");
} else{
printf("Dane dodane poprawnie\n");
}
fclose(fptr);
}
void readDatabase()
{
struct notification *object2=malloc(sizeof(struct notification));
fptr=fopen("G:\\file.txt","rb");
fread(object2,sizeof(struct notification),1,fptr);
while(!feof(fptr))
{
printf("Imie: %s\n", object2->name);
printf("Nazwisko: %s\n", object2->lastname);
printf("Cena: %s\n", object2->price);
printf("Opis: %s\n", object2->descreption);
printf("==========\n");
}
fclose(fptr);
}
int main() {
int i,option=0,check=0;
do{
printf("1) Dodaj rekord do bazy \n");
printf("2) Odczytaj rekordy z bazy \n");
printf("0) Zakoncz program \n");
scanf("%d", &option);
switch (option)
{
case 1:
insertRecord();
break;
case 2:
readDatabase();
break;
default:
break;
}
}while(check == 0); //petla dziala dopóki zmienna check bedzie równa 0
}
EDIT:
Correct insertRecord function:
void insertRecord()
{
fptr=fopen("G:\\file.txt","a+");
fflush(stdin);
struct notification *obj = malloc(sizeof(struct notification));
printf("Podaj imie: ");
gets(obj->name);
printf("Podaj nazwisko: ");
gets(obj->lastname);
printf("Podej cene: ");
gets(obj->price);
printf("Podaj opis usterki: ");
gets(obj->descreption);
strcat(notification.descreption,"\n");
if(fwrite(obj,sizeof(struct notification),1,fptr) != 1)
{
perror("Blad: ");
} else{
printf("Dane dodane poprawnie\n");
}
free(obj);
fclose(fptr);
}
Now ALL display and insert OK, but in file.txt I see Chinese characters, why?
There are a variety of problems in the readDatabase function
while(!feof)-is-always-wrong
the fread needs to be in the loop.
you don't need to malloc the memory, but if you do malloc memory, you should free it when you're done with it
you always need to check the return value from fopen, because it can and does fail, e.g. because the file is not found
With all that in mind, the readDatabase function should look like this
void readDatabase( void )
{
struct notification object2;
if ( (fptr = fopen("G:\\file.txt","rb")) == NULL )
{
printf( "File not found\n" );
return;
}
while ( fread( &object2, sizeof(struct notification), 1, fptr ) == 1 )
{
printf("Imie: %s\n", object2.name);
printf("Nazwisko: %s\n", object2.lastname);
printf("Cena: %s\n", object2.price);
printf("Opis: %s\n", object2.descreption);
printf("==========\n");
}
fclose(fptr);
}
Move this line:
fread(object2,sizeof(struct notification),1,fptr);
inside your while loop.
scanf("%d", &option); followed by gets() leads to trouble. The first does not consume the '\n' after the number and the second only reads in the short line '\n'.
Do not use scanf(). Do not use gets(). Use fgets(), then parse the input.
scanf() will leave new line character in input stream by default. you can use getchar() function to clear this new line character or you can flush the input buffer like this.
while ((ch = getchar()) != '\n' && ch != EOF);
but don't use fflush(stdin) because if the file stream is for input use, as stdin is, the behaviour is undefined, therefore it is not acceptable to use fflush() for clearing keyboard input. As usual, there are some exceptions, check your compiler's documentation to see if it has a (non-portable) method for flushing input.
Related
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 {...}
Im basically Writing a program that creates, reads, updates and
deletes records in a binary file.
Everything compiles correctly, no syntax errors, but I do have some
bugs.
KNOWN BUGS
1.) Imputing any strings does not work, using fgets
2.) Ctrl-D Does Work but outputs a 'default' error before it exits.
3.) Update does not work (Not my main issue at the moment as the others are more important for now.)
4?) I'm not sure if the menu is working how it's supposed to work. I
think the do while is correct, since in the menu if I select and hit
CTRL-D it does exit the program. Just wanna be sure.
Right now I just want to know why, It is skipping the courseName in
the inputs function.
Here is my code thus far
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
typedef struct{
char courseName [64];
char courseSched [4];
unsigned int courseHours;
unsigned int courseSize;} COURSE;
FILE *pfileCourse;
int courseNumber = 0;
//Prototypes
void inputDetails(COURSE *c);
void readCourseRecord();
void createCourseRecord();
void print_menu();
void modifyCourseInfo();
void deleteCourse();
void display(COURSE c);
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char *argv[]) {
char choice; // this is the choice
printf("Enter one of the following actions or press CTRL-D to exit\n");
printf("C - Create a new course record\n");
printf("R - Read an existing course record\n");
printf("U - Update an existing course record\n");
printf("D - Delete an existing course record\n");
do{
choice = getchar();
switch(choice) {
case 'c':
case 'C':
printf("YOU PICKED C for Create\n");
createCourseRecord();
break;
case 'r':
case 'R':
printf("This is Choice R\n");
readCourseRecord();
break;
case 'u':
case 'U':
printf("Here is where you update an existing course\n");
modifyCourseInfo();
break;
case 'd':
case 'D':
printf("here is where you Delete an existing course record\n");
deleteCourse();
break;
default:
printf("Wrong Choice!\n");
}
}while(choice != EOF);
return 0;
}
void createCourseRecord() {
COURSE data;
pfileCourse = fopen("courses.dat", "ab");
printf("Please Enter The Details of The Course\n");
inputDetails(&data);
fwrite(&data, sizeof(data), 1, pfileCourse);
fclose(pfileCourse);
printf("Course Has Been Created!\n");
}
void inputDetails(COURSE *c) {
printf("Enter a course number: \n");
scanf("%d", &courseNumber);
printf("Enter a Course Name: \n");
fgets(c->courseName, sizeof(courseName), stdin);
printf("Enter the course schedule (MWF or TR): \n");
fgets(c->courseSched, 4, stdin);
fflush(stdin);
printf("Enter the course credit hours: \n");
scanf("%d",&c->courseHours);
fflush(stdin);
printf("Enter Number of Students Enrolled: \n");
scanf("%d",&c->courseSize);
return;
}
void readCourseRecord(){
COURSE data;
int flag = 0;
int readCourseNumber = 0;
printf("Please Enter a Course Number to Display\n");
scanf("%d", &readCourseNumber);
fflush(stdin);
pfileCourse = fopen("courses.dat", "rb");
while((fread(&data, sizeof(data), 1, pfileCourse)) > 0) {
if(readCourseNumber == courseNumber)
{
display(data);
flag = 1;
}
}
fclose(pfileCourse);
if(flag == 0)
printf("Course not Found!\n");
}
void deleteCourse(){
int newCourseNum;
COURSE data;
FILE *file2;
printf("Please Enter The Course You Wish You Delete\n");
scanf("%d", &newCourseNum);
pfileCourse = fopen("courses.dat", "rb");
file2 = fopen("temp.dat", "wb");
rewind(pfileCourse);
while((fread(&data, sizeof(data), 1, pfileCourse)) > 0)
{
if(courseNumber != newCourseNum)
{
fwrite(&data, sizeof(data), 1, file2);
}
}
fclose(file2);
fclose(pfileCourse);
remove("courses.dat");
rename("temp.dat", "courses.dat");
printf("%d was Successfully deleted\n", newCourseNum);
}
void modifyCourseInfo()
{
COURSE data;
int newCourseNum, found = 0;
printf("Modify\n");
printf("Please Enter The Course You Wish You Modify\n");
scanf("%d", &newCourseNum);
pfileCourse = fopen("courses.dat", "rb+");
while ((fread(&data, sizeof(data), 1, pfileCourse)) > 0 && found == 0)
{
if (courseNumber == newCourseNum)
{
display(data);
printf("Please Enter New Details\n");
inputDetails(&data);
fseek(pfileCourse, - (long)sizeof(data), 1);
fwrite(&data, sizeof(data), 1, pfileCourse);
printf("Course Updated\n");
found == 1;
}
}
fclose(pfileCourse);
if(found == 0)
printf("ERROR: course not found\n");
}
void display(COURSE c){
printf("courseNumber:\t %d\n", courseNumber);
printf("courseName:\t %s\n",c.courseName);
printf("courseSched:\t %s\n",c.courseSched);
printf("courseName:\t %d\n",c.courseHours);
printf("courseSize:\t %d\n",c.courseSize);
}
It doesn't skip courseName, courseName just gets value '\n' because scanf function stops reading your input BEFORE white space. Scanf ignores any whitespace characters encountered before the next non-whitespace character. So you can just add
scanf("%d[^\n]", &courseNumber);
getchar();
after every scanf you have but I'd recommend you to use fgets function for every interactive input.
I am writing a menu system in C, the code works correctly but for some reason the first first time the while loop is entered for the menu it skips the getchar() command and runs through the while loop again, but the second time round it works?
Any ideas as to why it does this?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "structs.h"
int main(void)
{
FILE *fp = NULL;
char fileName[25], line[200], userInput = ' ';
int len;
while (fp == NULL)
{
printf("Enter The File To Load In: \n");
scanf("%s", fileName); // Ask User For File Name
fp = fopen(fileName, "r"); // Open File To Read
if (fp == NULL)
{
perror("Error While Loading File\n");
}
}
while (userInput != 'g')
{
printf(" |User System|\n");
printf("A) Save Current Data To A File\n");
printf("B) Enter Details\n");
printf("C) View Details\n");
printf("D) Amend Details\n");
printf("E) Search by Award Title\n");
printf("F) Search by Surname\n");
printf("G) Shut Down\n");
userInput = getchar();
if (userInput == 'c')
{
fgets(line, 200, fp);
len = strlen(line);
printf("%s", line);
userInput = getchar();
}
}
}
After 'scanf' use
getchar();
to consume extra newline. As 'scanf' can not discard newline, first iteration of 'getchar();' take the newline.
So you shold place getchar() after scanf as to consume extra newline('\n')
scanf("%s", fileName);
getchar();
It's better to use 'fgets' instead of scanf as file name may have space.
You can use 'fgets()' as
fgets(fileName, sizeof(fileName), stdin);
fileName[strlen(fileName)-1] = 0; //Replace newline with '\0' character
I am learning file handling in C.I have this code but it is not accepting string as an input to write it to a file.Any help will be appreciated.
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int main(void)
{
FILE * fp1;
fp1 = fopen("abc.txt","a+");
if(fp1==NULL)
{printf("An error occurred");
}
printf("Delete file?\n");
int a,c;
char name [20];
int flag=1;
int ch=1;
while(flag!=0)
{
printf("Enter id input \n");
scanf("%d",&a);
fprintf(fp1,"\n%d\t",a);
printf("Enter Name");
gets(name);
fputs(name, fp1);
printf("Enter No \n");
scanf("%d",&c);
fprintf(fp1,"\t%d\t",c);
printf("Write more then press 0 else 1");
scanf("%d",&ch);
if(ch==1)
{
flag=0;
}
}
fclose(fp1);
}
On running this code the code does not take an input after Enter Name and directly skips to Enter No.I want the output to be in a tabular form.
Use a getchar() after entering id because the \n of 1st scanf stays in buffer.
printf("Enter id input \n");
scanf("%d",&a);
getchar();
When you enter a number for scanf("%d",&a);, you type in a number and press the Enter key. The scanf consumes the number and leaves the newline character ('\n') in the standard input stream (stdin). When the execution of the program reaches gets(name);, gets sees the newline character and consumes it, storing it in name.
Firstly, never use gets as it is dangerous as it doesn't prevent buffer overflows. Use fgets instead:
fgets(name, sizeof(name), stdin);
Secondly, you have to get rid of the newline character. You can do this by flushing the stdin. Or you can simply scan and discard the newline character just after reading the number from scanf by changing
scanf("%d",&a);
to
scanf("%d%*c",&a);
%*c scans and discards a character.
gets() is deprecated, don't use it. you can still use scanf()...
as for the tabulation...think it through.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE* fp1;
fp1 = fopen("abc.txt", "a+");
if (fp1 == NULL) {
printf("An error occurred");
}
int a, c;
char name [20];
int flag = 1;
int ch = 1;
while (flag != 0) {
printf("Enter id input:\n");
scanf("%d", &a);
fprintf(fp1, "%d\t", a);
printf("Enter Name:\n");
scanf("%s", name);
fprintf(fp1, "%s\t", name);
printf("Enter No:\n");
scanf("%d", &c);
fprintf(fp1, "%d\n", c);
printf("Again (0) or Exit(1) ?:\n");
scanf("%d", &ch);
if (ch == 1) {
flag = 0;
}
}
fclose(fp1);
return 0;
}
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.