I am reading from a file, however if it doesn't exist is meant to print 'Read error' but for some reason it is printing read error twice and I don't know why
int loadFlights(char flightDatabase[50], int totalflights, flight_t f[MAX_NUM_FLIGHTS])
{
int counter;
FILE *fp;
fp = fopen("database.txt", "r");
if(fp == NULL) { /************************statement with problem*/
printf("Read error\n");
return 1;
}
fscanf(fp, "%d", &totalflights);
if (totalflights > 5) {
totalflights = 5;
}
for(counter = 0; counter <= totalflights-1; counter++)
{
fscanf(fp, "%s %d %d %d %d %s %d %d %d %d", f[counter].flightcode,
&f[counter].departure_dt.month, &f[counter].departure_dt.date,
&f[counter].departure_dt.hour, &f[counter].departure_dt.minute,
f[counter].arrival_citycode, &f[counter].arrival_dt.month,
&f[counter].arrival_dt.date, &f[counter].arrival_dt.hour,
&f[counter].arrival_dt.minute);
}
fclose(fp);
return totalflights;
}
I've tried putting an if statement around the Read Error if statement saying if its already been printed don't print again however it still seems to be printing.
int main(void)
{
flight_t f[MAX_NUM_FLIGHTS];
int totalflights = 0, menu;
char flightDatabase[50] = "database.txt";
while (menu != 5)
{
print_Menu();
scanf("%d", &menu);
while ((menu < 0) || (menu > 5)) {
printf("Invalid choice\n");
print_Menu();
scanf("%d", &menu);
}
if (menu == 1)
{
addFlight(f, totalflights);
totalflights++;
}
else if (menu == 2)
{
displayFlight(f, totalflights);
}
else if (menu == 3)
{
saveFlight(f, flightDatabase, totalflights);
}
else if (menu == 4)
{
loadFlights(flightDatabase, totalflights, f);
totalflights = loadFlights(flightDatabase, totalflights,f);
}
}
return 0;
}
This is the code where I call on the function.
This is where the problem is:
// Some code
else if (menu == 4)
{
loadFlights(flightDatabase, totalflights, f);
totalflights = loadFlights(flightDatabase, totalflights,f);
}
These are two consecutive calls to loadFlights while the first call doesn't catch the return value. You can get rid of the first one and it should behave the way you expect it to.
Additionally, I see a problem:
while (menu != 5)
At this point, menu is uninitialised, will hold a random value. You might want to either initialise it to zero or 5 or whatever is legal for that data type.
I've tried putting an if statement around the Read Error...
These are the patch works, that are really dangerous to have. Its usually expected to debug the code and find out whats the exact problem rather than adding a patch to cover up an existing bug.
Related
I am using the frwite feature to save previous math equation result data and the code works when using integers but if I use char values (which I am trying to implement in order to make a certain future feature possible), I get weird values back. For example when the result 50 was saved, when the data was loaded I got the following:
2
2
The following is the code I wrote in question:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <cbm.h>
int integer1;
int integer2;
int integer3;
int option;
char save;
char c;
FILE *fp; //?????
void startup() {
textcolor (COLOR_WHITE);
bordercolor (COLOR_BLACK);
bgcolor (COLOR_BLACK);
clrscr ();
}
void get2nums() {
printf("FIRST NUMBER?\n");
scanf("%d", &integer1);
printf("SECOND NUMBER?\n");
scanf("%d", &integer2);
}
void addition() {
get2nums();
save = integer1 + integer2; //save into the save variable which will provide input to the save file function
printf("%d", save);
printf("\n");
}
void subtraction() {
get2nums();
save = integer1 - integer2; //save into the save variable which will provide input to the save file function
printf("%d", save);
printf("\n");
}
void multiplication() {
get2nums();
save = integer1 * integer2; //save into the save variable which will provide input to the save file function
printf("%d", save);
printf("\n");
}
void division() {
get2nums();
if(integer2 == 0)
printf("Div by 0 undefined\n");
else
save = integer1 / integer2; //save into the save variable which will provide input to the save file function
printf("%d with %d remainder", integer1 / integer2, integer1 % integer2);
printf("\n");
}
static void savedata(void) {
char data_out = save; //Data that goes into the file
//Saving
_filetype = 's'; //Does this set the file as a .SEQ?
if ((fp = fopen ("CALCDATA", "w")) == 0) {
printf("ERROR COULD NOT OPEN FILE\n\r"); //Error handler
printf("CHECK DISK DRIVE\n");
exit(1);
}
fwrite (&data_out, sizeof(data_out), 1, fp);
fclose (fp);
}
static void loaddata(void) {
_filetype = 's';
if ((fp = fopen ("CALCDATA", "r")) == 0) {
printf("ERROR COULD NOT OPEN FILE\n\r");
printf("CHECK DISK DRIVE\n");
exit(1);
}
while (1) {
c = fgetc (fp);
if (feof (fp)) {
break;
}
printf("\n");
printf ("%c\n", c);
}
fclose (fp);
}
void debug() {
printf("%d", save);
}
int main() {
startup();
for( ;; ) { // uncomment this line and below for infinite looping
printf("\n");
printf("ADVANCED CALCULATOR VERSION 0.9\n");
//printf("CODED BY REDACTED\n");
//printf("BUILD DATE: 12/12/2022\n");
//delay(5000);
//clrscr ();
printf("CALCULATOR OPTIONS ARE:\n");
printf("1. ADDITION\n");
printf("2. SUBTRACTION\n");
printf("3. MULTIPLICATION\n");
printf("4. DIVISION\n");
printf("5. SAVE PREVIOUS\n");
printf("6. LOAD SAVE\n");
printf("7. QUIT\n");
// printf("8. DEBUG\n");
// printf("5. ADVANCED OPERATIONS\n"); // TODO
printf("PLEASE SELECT YOUR OPTION.\n");
scanf("%d", &option);
if(option == 1)
addition();
else if(option == 2)
subtraction();
else if(option == 3)
multiplication();
else if(option == 4)
division();
else if(option == 5)
savedata();
else if(option == 6)
loaddata();
else if(option == 7)
exit(1);
//else if(option == 8)
//debug();
else
printf("INVALID RESPONSE\n");
} // uncomment this line for infinite looping
return 0;
}
I checked using the function I wrote called debug to see if the results of the previous math problem were being put in the variable correctly and they were. This leads me to the conclusion that it is something with the way the save or load code is written that is causing this issue. Also to note, I have previously gotten char data to save, but only when it was predefined with the char data_out variable written as char data_out[]. Any information on this issue helps, thanks!
How do I write a C program to enter a number from the keyboard and store it in a text file called number.dat. If the number exists in the file, display an error message. Program should allow to input numbers until the user inputs -99.
I tried this question, but I could not find how to check whether the integer already exists in the file.
This is my C code answer:
#include <stdio.h>
int main(void) {
int num;
FILE *xPtr;
xPtr = fopen("number.dat", "a");
while (num = -99) {
printf("Enter a number : ");
scanf("%d", &num);
if (num == -99)
break;
fprintf(xPtr, "%d\n", num);
}
return 0;
}
I could not find how to check whether an integer already exists in the file.
Can you please give me a solution for this matter?
There are a few things that could be improved. First of all, your while loop is using an assignment operator for the conditional expression:
while(num = -99)
Instead of assigning it to 99 at the beginning of the loop each time, you could do this:
while(num != -99)
Since you want the block inside of the loop to execute when num is not equal to -99. I would also convert it to a do-while loop, since you are not assigning num before you enter the loop the first time. When you are in the loop, you should be opening an closing the file so it can keep track of any numbers you add. In order to check your file you will need to read AND append, it is now currently set to only append. To read and append you will do the following:
xPtr = fopen("number.dat", "a+");
It might be helpful to add a function called has_num or whatever you choose, which takes the FILE* and checks for an int returning 1 if found and 0 if not. So you will modify your if statement to be
if (num != -99 && !has_num(xPtr,num))
{
fprintf(xPtr, "%d\n", num);
}
So with all of those changes, your code will become
#include <stdio.h>
int has_num(FILE* file, int num)
{
int curr;
int fnd = 0;
while (!fnd && (fscanf(file, "%d\n", &curr) != EOF))
{
fnd = (curr == num);
}
return fnd;
}
int main(void)
{
int num;
FILE *xPtr ;
do
{
xPtr = fopen("number.dat", "a+");
printf("Enter a number : ");
scanf("%d", &num);
if (num != -99 && !has_num(xPtr,num))
{
fprintf(xPtr, "%d\n", num);
}
fclose(xPtr);
} while (num != -99);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *fp; //create a pointer to FILE
char c,n,num;
printf("Enter a Number : ");
scanf("%c",&n);
if(n== -99){
// printf("Enter number greater than -99");
exit(0);
}
else{
fp = fopen("numbers.dat", "r+"); //read file
while ((c = getc(fp)) != EOF) {
num = c;
if(num==n){
printf("Included Number");
exit(0);
}
}
fp = fopen("numbers.dat","w+"); //write new number to file
putc(n, fp);
}
}
You program should successfully append numbers typed by the user to the file, but it has a few problems:
you do not check if fopen() successfully opened the file, you have undefined behavior if fopen() returns NULL.
you do not check if scanf() encountered an input failure. Entering a character that os not a number will cause undefined behavior, most likely an infinite loop appending the previously entered number if any.
you do not close the file. This will not have any adverse effect because all files are automatically closed upon program exit, but it is good style to close them explicitly.
of course you do not check if the number already exists in the file.
For the last problem, you should fopen() the file for both read and write, rewind the file and read all lines, checking if the number is present.
Here is a modified version:
#include <stdio.h>
int main(void) {
int c, num, num1, found;
FILE *xPtr = fopen("number.dat", "w+");
if (xPtr == NULL) {
printf("cannot open file number.dat\n");
return 1;
}
for (;;) {
printf("Enter a number: ");
if (scanf("%d", &num) != 1) {
if (feof(stdin))
break;
printf("invalid input\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
break;
} else {
if (num == -99)
break;
rewind(xPtr);
found = 0;
for (;;) {
/* skip all characters that cannot start a number */
if (fscanf(xPtr, "%*[^-+0-9]") == EOF)
break;
if (fscanf(xPtr, "%d", &num2) == 1) {
if (num == num2) {
found = 1;
break;
}
} else {
getc(xPtr); // consume a byte
}
}
if (found) {
printf("number is already in the file\n");
} else {
/* append the number */
fseek(xPtr, 0L, SEEK_END);
fprintf(xPtr, "%d\n", num);
}
}
}
fclose(xPtr);
return 0;
}
I'm writing a program that allows multiple users to create, save, and load data to files. I'm running into an issue where I can't find seem to figure out a logic that doesn't allow users to create duplicate file names.
Here is the important working part of my code thus far, but where my issues are. The variable user is assigned at the launch of my program where the user must enter their username and password.
else if (selection == 6)
{
int i;
int d;
printf("Please enter a file name: ");
scanf("%s", filename);
newFile = fopen(filename, "a+");
Record = fopen("records.txt", "a+");
fprintf(Record, "%s %s\n", user, filename);
for (i = 0; i < icount; i++)
{
fprintf(newFile, "%d ", ints[i]);
}
for (d = 0; d < dcount; d++)
{
fprintf(newFile, "%lf ", doubles[d]);
}
fclose(Record);
fclose(newFile);
}
else if (selection == 7)
{
printf("Please enter a file name: ");
scanf("%s", filename);
Record = fopen("records.txt", "a+");
while (fscanf(Record, "%s %s", curuser, curfile) != EOF)
{
if (strcmp(user, curuser) == 0 && strcmp(filename, curfile) == 0)
{
int c;
//fopen(newFile, "a+");
newFile = fopen(filename, "a+");
if (newFile) {
while ((c = getc(newFile)) != EOF)
{
putchar(c);
}
fclose(newFile);
break;
}
}
else
{
printf("You don't have access to this file.\n");
break;
}
}
}
Somewhere in selection 6, I'm trying to say in code, "Okay user, enter a file, unless the name already exists." What I tried was
while (fscanf(Record, "%s %s", curuser, curfile) != EOF)
{
if (strcmp(curfile, filename) == 0)
{
break;
}
else
{
fprintf(Record, "%s %s\n", user, filename);
fclose(Record);
}
}
and I'm unable to figure out why this won't work. I tried placing this code right below Record file declaration.
I think the issue may be that when the record file is empty, the != EOF line is causing it to break, but I also can't figure out a way to initially get one user and filename in the record before probing the rest of the users for their filenames. Any guidance in the right direction would be appreciated!
I think you can solve your problem by cutting the while loop in several parts:
do the fscanf
check for end of file
check for "user found"
And finally,
write user if not previously in file.
I would have written something like:
int record_found = 0;
int scanf_res;
while (1)
{
/* do the fscanf */
scanf_res = fscanf(Record, "%s %s", curuser, curfile);
/* test for end of file */
if (EOF == scanf_res)
{
/* end of file reached */
break;
}
/* if fscanf has mado 2 conversion AND
filename is curfile */
if ((2 == scanf_res) && (strcmp(curfile, filename) == 0))
{
record_found = 1;
break;
}
}
if (!record_found)
{
/* add user if needed */
fprintf(Record, "%s %s\n", user, filename);
}
/* and close file in all cases */
fclose(Record);
I have a program that retrieves some numbers from a file into an array. The last problem that I have is that my program keeps running even though it cannot open the file, instead of ending it. Even when it says program is over, the menu from main appears again but doesn't show any data
int main (void)
{
int choice, max, min;
float avg;
int test[MAX_NUMBER_OF_STUDENTS];
int file_opened;
int number_of_students;
file_opened = get_test_scores(test, &number_of_students);
if (file_opened == 0)
{
do
{
choice = menu();
switch (choice)
{
case 0: printf("\nProgram is over.\n");
break;
case 1: test_avg(&avg, test, number_of_students);
printf("\nAverage score on test = %5.2f\n", avg);
break;
case 2: test_max_min(number_of_students, &max, &min, test);
printf("\nMaximum score = %3d\n"
"Minimum score = %3d\n", max, min);
break;
case 3: print_test(test,number_of_students);
break;
default:
printf("This should never happen!");
}
} while (choice != 0);
}
return 0;
}
int get_test_scores(int test[], int* size)
{
FILE* sp_input; // Pointer to the input stream (from a file)
int i;
sp_input = fopen("a20.dat", "r");
if (sp_input == NULL)
printf("\nUnable to open the file a20.dat\n");
else
{
while( fscanf(sp_input, "%d", &test[i])!=EOF)
{
i=i+1;
++*size;
}
fclose(sp_input); // Close the stream
}
return 1;
}
Yes, it keeps running...
if (file_opened == 0)
{
do
{
means that if the file has not been opened, to do the loop. You want:
if (file_opened != 0)
See also comments about other bugs.
i have this program that asks users to enter info stores it in file and allows u to edit entries or add new ones or delete ones by setting gross salary to 0.
However when i try to modify a name , it doesn't modify , and when i try to modify gender, it causes an infinite loop can any1 tell me whats wrong?
And i think there something wrong with my break statements i made within the loop , thanks in advance
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int employee_number;
char employee_name[20];
char employee_sex;
int employee_gross_salary;
}information;
int main()
{//open main function
information customer;
int i;
int choice;
int number;
int choice2;
int number2;
FILE *fptr = fopen("emp.dat", "wb+");
//asking user to enter atleast 5 customers into datarecords
for(i = 0; i<1;i++)
{//open for
printf("enter employee's number\n");
scanf("%d",&customer.employee_number);
getchar();
printf("enter the employee's name\n");
scanf("%s", customer.employee_name);
getchar();
printf("enter employee's gender\n");
scanf("%d",&customer.employee_sex);
getchar();
printf("enter employee's salary\n");
scanf("%d",&customer.employee_gross_salary);
getchar();
fwrite(&customer,sizeof(customer),1,fptr);
}//close for
for(;;)
{//open for
printf("\n what would you like to do\n1]Add entry\n 2]Delete entry \n3]Modify entry\n4]view entries\n5]exit\n");
scanf("%d", &choice);
if(choice == 5)
{break;}
else if(choice == 1)
{//open else if
fseek(fptr,0, SEEK_END);// check the parameters here
printf("enter new employee's number\n");
scanf("%d",&customer.employee_number);
getchar();
printf("enter the new employee's name\n");
scanf("%s", customer.employee_name);
getchar();
printf("enter new employee's gender\n");
scanf("%d",&customer.employee_sex);
getchar();
printf("enter new employee's salary\n");
scanf("%d",&customer.employee_gross_salary);
getchar();
fwrite(&customer,sizeof(customer),1,fptr);
continue;
}//close else if
else if( choice == 2)
{//open else if
printf("enter the employee number of person\n");
scanf("%d",&number);
fseek(fptr,0,SEEK_SET);
while((fread(&customer,sizeof(customer), 1,fptr))!=NULL)
{//open while
if(customer.employee_number == number)
{//open if
customer.employee_gross_salary = 0;
}//close if
}//close while
continue;
}//clsoe else if
else if(choice == 3)
{//open else if
printf("enter the employee number of the employee you would like to modify\n");
scanf("%d",&number2);
printf("what would you like to modify\n");
scanf("%d", &choice2);
fseek(fptr,0,SEEK_SET);
while((fread(&customer, sizeof(customer),1,fptr))!= NULL)
{//open while within else if
//1 to midify name, 2 to modify gender 3 for salary
if(customer.employee_number == number2)
{//open if
if(choice2 == 1)
{
printf("enter new name\n");
scanf("%s",customer.employee_name );
break;
}
else if(choice2 == 2)
{
printf("enter new gender");
scanf("%d", &customer.employee_sex);
break;
}
else if(choice2 == 3)
{
printf("enter new gross salary\n");
scanf("%d", &customer.employee_gross_salary);
break;
}
}//close if
}//close while within else if
continue;
}//close else if
else if(choice == 4)
{
fseek(fptr,0,SEEK_SET);
while((fread(&customer,sizeof(customer),1,fptr))!= NULL)
printf("\n%d\t%s\t%c\t%d\n", customer.employee_number,customer.employee_name,customer.employee_sex,customer.employee_gro ss_salary);
continue;
}
}//close for
return 0;
}//close main function
This is NOT the answer for your debug, just some advice for refactoring your code and future writing:
1.
Avoid using break and continue, they are flow breaker, bug sources, bad and evil, it is the same for go to, they are here for specific no-other-way cases.
You can do something like:
int end = 0,
choice = 0;
do
{
fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
while(fscanf(stdin, "%d", &choice) != 1){}
if(choice == 1)
{
//Do stuff
}
else if (choice == 2)
{
//Do other stuff
}
else if (choice == 3)
{
//Do another stuff
}
else
{
end = 1;
}
}while(end == 0);
return 0;
No continue, no break, easier to modify, easier to write, easier to read, shorter, in two word: way better
2.
Write in english, always, you have a full keyboard and do not pay by letter, it is almost as fast to type the entire word, and help a lot other to understand.
Also, it will help you to make less error when you write text or code.
3.
You can declare multiple variable at once if they are of the same type:
int var1;
int var2;
int var3;
...
Is long and repetitive, instead you can write:
int var1,
var2,
var3;
A good habit can be to always initialize variables, it help prevent some bug:
int var1=0,
var2=0,
var3=0;
4.
Whenever you use a function, test its return, there is a lot of bug that happen from thinking "it is a stdio function, it is bug-proof". As exemple, your fopen of emp.dat. It can fail (and in fact will fail at some point).
FILE *fptr = fopen("emp.dat", "wb+");
if (fptr == NULL)
{
fprintf(stderr, "Error while opening emp.dat\n");
return -1;
}
5.
If you are a begginner (there is no shame about that, everyone begin at some point, and we can say everyone is still begginning even after 10+years of coding), write your algorithm first, then code. Exemple:
//Get user's choice
//If user choice is do stuff
//Do stuff
//If it is do other stuff
//Do other stuff
//If it is do another stuff
//Do another stuff
//Else if he want to quit
//Quit
Which then become
int choice=0, //User's choice
end=0; //End of program
do
{
//Get user's choice
fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
while(fscanf(stdin, "%d", &choice) != 1){}
//If user choice is do stuff
if(choice == 1)
{
//Do stuff
}
//If it is do other stuff
else if(choice == 1)
{
//Do other stuff
}
//If it is do another stuff
else if(choice == 1)
{
//Do another stuff
}
//Else if he want to quit
else
{
//Quit
end = 1;
}
}while (end == 0);
return 0;
It also prevent you from going to comment your code weeks later when you don t know anymore why you did that or that stuff.
6.
Log, log, log, especially at debug!
You can put it on stderr if you want, so you can separate it from your output.
Exemple:
int end = 0,
choice = 0;
fprintf(stderr, "Start\n");
do
{
fprintf(stderr, "\tBegin loop\n");
fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
while(fscanf(stdin, "%d", &choice) != 1){}
fprintf(stderr, "\tChoice is: %d\n", choice);
if(choice == 1)
{
fprintf(stderr, "\t\tStarting do stuff\n");
//Do stuff
fprintf(stderr, "\t\tEnding do stuff\n");
}
else if (choice == 2)
{
fprintf(stderr, "\t\tStarting do other stuff\n");
//Do other stuff
fprintf(stderr, "\t\tEnding do other stuff\n");
}
else if (choice == 3)
{
fprintf(stderr, "\t\tStarting do another stuff\n");
//Do another stuff
fprintf(stderr, "\t\tEnding do another stuff\n");
}
else
{
fprintf(stderr, "\t\tEnd order\n");
end = 1;
}
fprintf(stderr, "\tEnd of loop\n");
}while(end == 0);
fprintf(stderr, "End\n");
return 0;
So you know when and where is your program right now, it is a HUGE help for debug!
That s all I have in mind right now, hope it can help you.
Also, welcome to Stack Overflow.
Edit:
Thanks to chunk, another important point:
7.Always checking scanf for valid user's input. User's input can and will be almost eveything, and will at some point not be what you think, test it, always. (it is not valid only for (f)scanf, but for EVERY ways you get your data from other sources but your own source code)
int check = 0;
fprintf(stderr, "\tBegin loop\n");
fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
check = fscanf(stdin, "%d", &choice);
if(check != 1)
{
fprintf(stderr, "Bad input\n");
return -1;
}
fprintf(stderr, "\tValid choice is: %d\n", choice);
This way, any other input but a decimal number will be discarded and will close the program, of course you can do it better.
int check = 0;
fprintf(stderr, "\tBegin loop\n");
fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
while(fscanf(stdin, "%d", &choice) != 1)
{
fprintf(stderr, "Bad input!\n");
}
fprintf(stderr, "\tValid choice is: %d\n", choice);
In this version, when the user type something invalid, he just have to try again.
In addition to DrakaSAN's answer I would add that you should always flush the input buffer when you take character/string input after taking integer input.
One way to flush the input buffer is to use getchar():
while ((ch = getchar()) != '\n');
But if the user gives the input as "123 abc\n" (as mentioned by chux in comment) assuming 123 goes to the integer variable and "abc" to the character array, then there are ways to resolve this:
//can be modified according to programmer's requirements
int a;
char arr[10],ch;
scanf("%d",&a);
while((ch=getchar())==' ' || ch=='\t' || ch=='\n') //loop until non-whitespace character
{
if (ch=='\n')
{
ch=getchar();
break;
}
}
if (ch!='\n') //ch contains the first character of the character array
{
arr[0]=ch;
gets(arr+1);
}
else //if two consecutive new lines after integer, string contains nothing
arr[0]='\0';
You need to write the results when choice == 2 and choice == 3 before the continue, like
fseek(fptr, -sizeof(customer), SEEK_CUR);
fwrite(&customer,sizeof(customer), 1, fptr);