reading inputs from input file, keep getting infinite loop - c

after tirelessly looking for an explanation I've decided to ask the greats at stackoverflow. So I'm currently trying to read each input line by line from a file called data.txt. The program works perfectly fine using simple scanf and such, but when I want to read input values from a file the program only reads the first 3 lines of the txt and it keeps repeating in an infinite loop. My code is shown below. I kept out the majority of my code in case others may be tempted to use it. Program will just read 1, 12, 0 infinitely. sample data.txt file is shown below
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
// Global variables
char *Hstring = NULL;
int maxLength, parity;
char *temp = NULL;
int userChoice = 0;
void option1() {
// User inputs length and even or odd parity bit
printf("\n*** Maximum Code Length: %d", maxLength);
//scanf("%d",&maxLength);
printf("\n*** Parity: %d", parity);
//scanf("%d",&parity);
// allocate memory for hamming string based on maximum length and
//size of character element
Hstring = (char *)malloc(maxLength * sizeof(char));
return;
}
void option2() {
/* declare local vars */
int aLength, k, parBits, parValue, errorPos, i, j;
/* prompt for hamming code as a "string"*/
printf("\nEnter the Hamming Code: ");
scanf("%s", Hstring);
temp = Hstring;
aLength = strlen(Hstring);
parBits = ceil(log(aLength) / log(2));
}
int main() {
FILE *fp;
fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("ERROR OPENING THE FILE\n");
}
fscanf(fp, "%d %d %d", &userChoice, &maxLength, &parity);
//end file open
while (userChoice != 3) {
printf("\nEnter Selection: %d", userChoice);
//scanf("%d",&userChoice);
switch (userChoice) {
case 1:option1();
break;
case 2:option2();
break;
case 3:
printf("\n*** Program Terminated Normally\n");
break;
default: printf("invalid input please input another number\n\n");
break;
}
}
/* print out menu, prompt for choice, and call appropriate procedure
until user quits */
return 1;
}
SAMPLE data.txt
1
12
0
2
1000
1
Code starts to loop when it reads the third integer(parity) in option1()
Any help would be appreciated. Thank you!

You never modify userChoice in your while loop, so it's gonna loop forever.
Anyways, even if you were using fscanf in the while loop, and therefore reading the whole file until you find userChoice == 3, it's a bad idea to have your loop termination condition only depending on the content of a file, you should also check the result of fscanf for termination of the file. Your example data would still loop forever because it contains no 3.

The answer here https://stackoverflow.com/a/53475412/4386427 is correctly describing the problem, i.e. that you have an endless loop because userChoice is only read once.
Here is a suggestion for a fix.
int main() {
FILE *fp;
fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("ERROR OPENING THE FILE\n");
}
while (userChoice != 3) {
// Check that exactly 3 items are read from the file.
// If not terminate the program
if (fscanf(fp, "%d %d %d", &userChoice, &maxLength, &parity) != 3) {
printf("Illegal input from file or EOF. Terminating program\n");
break;
}
switch (userChoice) {
case 1:option1();
break;
case 2:option2();
break;
case 3:
printf("\n*** Program Terminated Normally\n");
break;
default: printf("invalid input please input another number\n\n");
break;
}
}
return 1;
}

Related

How to check whether a given integer already exists in a file

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

My case 2 doesnt seem to be reading my .txt files in C programming

I've been working on this program for my job that I'm trying to make an inventory of tools. I'm very new to programming if there is an alternative rout to take on this I'm open to looking in to it.
My first case works. All it does is ask the user for a nomenclature, part number(P/N), and serial number (S/N).
The second case I'm trying to make it print the list of data.
My goal for this is to get my problem fixed for my second case
#include<stdio.h>
#include<stdlib.h>
main()
{
FILE * fp;
int qty;
int menu;
char nomen[26];
char pN[26];
char ans;
//Test to see if file exist
fp = fopen("Metro Inventory.txt", "w");
if (fp == NULL)
{
printf("*Error opening file*");
fprintf(fp,"*Error opening file*");
exit(1);
}
//Intro Header
fprintf(fp,"List of Special Tools:");
fprintf(fp,"\t\t\tPart Number:");
fprintf(fp,"\t\t Quantity:\n\n");
printf("Metro Aviation Tools List\n\n");
printf("What would you like to do?\n");
scanf("%d", &menu);
//loop of switch asking for nomenclature
do
{
switch (menu)
{ //Case 1 adds new content
case(1):
{
printf("Enter Nomenclature(no spaces):\n");
scanf("%s", nomen);
fputs(nomen, fp);
fputs("\t\t\t",fp);
//Part Number
printf("What is the part number?\n");
scanf("%s", pN);
fputs(pN, fp);
fputs("\t\t\t", fp);
//Quantity
printf("What is the quantity?\n");
scanf("%d", &qty);
fprintf(fp,"%d",qty);
fputs("\n", fp);
break;
fclose(fp);
}// Case 2 Edits content
case(2):
{
int c;
fp = fopen("Metro Inventory.txt", "r");
if (fp)
{
while ((c = getc(fp)) != EOF)
putchar(c);
fclose(fp);
}
fclose(fp);
break;
}
default : printf("Thank you");
break;
}//end switch
printf("To add tool type Y.\n To exit type N.\n");
getch();
scanf("\n%c", &ans);
//loop
}
while ((ans == 'Y')||(ans == 'y'));
if ((ans == 'N')||(ans=='n'));
{
exit(1);
}
getch();
return 0;
}
I haven't done file I/O for C for quite a long time however, a quick look into your program reveals that the time when you set/modify the value of menu is at line 26/27. Then, your loop starts at line 29. After that, there isn't any instruction to set/modify your menu value.
Later on at line 73 to 75, you are asking for input before the loop scope ends. This input is only used later on in another loop. What I'd suggest to you is to remove the whole switch case structure and allow the program to start away continue to do whatever you want to do. As there isn't any explanation too on why should the user pick 1 for menu or 2.
Edit
It seems that you do not understand my initial comment, so I've taken the liberty to change some parts of your code.
Changes done:
Main() - For C programming, it has to have a type for the program entry point. Either void or int. Should you do int main() make sure to place return 0; before the last braces. Look at the modified code below for clarity.
Position of the code where the input for menu is supposed to happen. I placed it inside the loop so that the user will be prompt every time the loop restarts.
In my initial answer or comment, I've said that in your original code, the point where you modify your variable required for the switch case to work only once and it happens before the loop.
You must think from 1 line to another. What happens at line 1. How does line 1 affect line 2. In this example of yours, at line 26/27, you've set the value of menu to which ever input by the user (input validation is another topic). At that point, it is still linear, nothing loops so it means that your from the point you set the menu (line 26/27) to the point where the program exits (or ends) the value of menu remains static, unchanged.
Removed exit(1); I assumed you wanted the program to end if fp returns null and/or the user has chosen other input for ans. The issue of having an exit point is solved with the next modification I've made (refer to item 4).
Rearranged the code so that if (fp != null) which is the else part in the new code (refer to line 20) the program will allow the file to be written to. And should fp returns null, the whole program will exit with a return 0;.
Modified code
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE * fp;
int qty;
int menu;
char nomen[26];
char pN[26];
char ans;
//Test to see if file exist
fp = fopen("Metro Inventory.txt", "w");
if (fp == NULL)
{
printf("*Error opening file*");
fprintf(fp,"*Error opening file*");
}
else
{
//Intro Header
fprintf(fp,"List of Special Tools:");
fprintf(fp,"\t\t\tPart Number:");
fprintf(fp,"\t\t Quantity:\n\n");
do
{
printf("Metro Aviation Tools List\n\n");
printf("What would you like to do?\n");
scanf("%d", &menu);
//loop of switch asking for nomenclature
switch (menu)
{ //Case 1 adds new content
case(1):
{
printf("Enter Nomenclature(no spaces):\n");
scanf("%s", nomen);
fputs(nomen, fp);
fputs("\t\t\t",fp);
//Part Number
printf("What is the part number?\n");
scanf("%s", pN);
fputs(pN, fp);
fputs("\t\t\t", fp);
//Quantity
printf("What is the quantity?\n");
scanf("%d", &qty);
fprintf(fp,"%d",qty);
fputs("\n", fp);
break;
fclose(fp);
}
// Case 2 Edits content
case(2):
{
int c;
fp = fopen("Metro Inventory.txt", "r");
if (fp)
{
while ((c = getc(fp)) != EOF)
putchar(c);
fclose(fp);
}
fclose(fp);
break;
}
default :
printf("Thank you");
break;
}//end switch
printf("To add tool type Y.\n To exit type N.\n");
getch();
scanf("\n%c", &ans);
//loop
}while ((ans == 'Y')||(ans == 'y'));
}
return 0;
}

scanf validation sits and waits for another input. Why?

I was working on this sample exercise, and everything works as I would like it to, but there is one behavior I don't understand.
When providing input: if I make consecutive invalid entries everything seems to work great. But if I enter a number different from 1,2,3 in the case of the first question, or 1,2 in the case of the second question, the program just sits there until a new input is given. If another invalid entry is made, it goes back to the error "invalid entry" message, and if an appropriate number is entered, everything moves along fine.
I do not understand why it stops to wait for a second input...anyone?
Thanks guys.
#include <stdio.h>
static int getInt(const char *prompt)
{
int value;
printf("%s",prompt);
while (scanf("%d", &value) !=1)
{
printf("Your entry is invalid.\nGive it another try: %s", prompt);
getchar();
scanf("%d", &value);
}
return value;
}
int main() {
int wood_type, table_size, table_price;
printf("Please enter " );
wood_type = getInt("1 for Pine, 2 for Oak, and 3 for Mahogany: ");
printf("Please enter ");
table_size = getInt("1 for large, 2 for small: ");
printf("\n");
switch (wood_type) {
case 1:
table_price = (table_size == 1)? 135:100;
printf("The cost of for your new table is: $%i", table_price);
break;
case 2:
table_price = (table_size == 1)? 260:225;
printf("The cost of for your new table is: $%i", table_price);
break;
case 3:
table_price = (table_size == 1)? 345:310;
printf("The cost of for your new table is: $%i", table_price);
break;
default:
table_price = 0;
printf("The cost of for your new table is: $%i", table_price);
break;
}
}
You most likely need to flush your input buffer (especially with multiple scanf calls in a function). After scanf, a newline '\n' remains in the input buffer. fflush does NOT do this, so you need to do it manually. A simple do...while loop works. Give it a try:
edit:
static int getInt(const char *prompt)
{
int value;
int c;
while (printf (prompt) && scanf("%d", &value) != 1)
{
do { c = getchar(); } while ( c != '\n' && c != EOF ); // flush input
printf ("Invalid Entry, Try Again...");
}
return value;
}
The blank line you get if you enter nothing is the normal behavior of scanf. It is waiting for input (some input). If you want your routine to immediately prompt again in the case the [Enter] key is pressed, then you need to use another routine to read stdin like (getline or fgets). getline is preferred as it returns the number of characters read (which you can test). You can then use atoi (in <stdlib.h>) to convert the string value to an integer. This will give you the flexibility you need.
example:
int newgetInt (char *prompt)
{
char *line = NULL; /* pointer to use with getline () */
ssize_t read = 0; /* number of characters read */
size_t n = 0; /* numer of chars to read, 0 no limit */
static int num = 0; /* number result */
while (printf ("\n %s ", prompt) && (read = getline (&line, &n, stdin)) != -1)
{
if ((num = atoi (line)))
break;
else
printf ("Invalid Input, Try Again...\n");
}
return num;
}
If some invalid input is entered, it stays in the input buffer.
The invalid input must be extracted before the scanf function is completed.
A better method is to get the whole line of input then work on that line.
First, put that input line into a temporary array using fgets(),
then use sscanf() (safer than scanf because it guards against overflow).
#include <stdio.h>
int main(int argc, const char * argv[]) {
char tempbuff[50];
int result, d , value;
do
{
printf("Give me a number: ");
fgets( tempbuff, sizeof(tempbuff), stdin ); //gets string, puts it into tempbuff via stdin
result = sscanf(tempbuff, "%d", &value); //result of taking buffer scanning it into value
if (result < 1){ //scanf can return 0, # of matched conversions,
//(1 in this case), or EOF.
printf("You didn't type a number!\n");
}
}while (result < 1);
//some code
return 0;
}
Knowledge from: http://www.giannistsakiris.com/2008/02/07/scanf-and-why-you-should-avoid-using-it/

Issue with a nested for loop

I'm currently working on a program that asks a user to enter a secret word. The user's input is then compared with a list of words which are on a text file. The user has 3 chances to enter the word. If correct, the program restarts the loop. This continues until all the words have been guessed correctly. If a word is incorrectly guessed 3 times, the program should terminate. My problem is with the 3 guesses loop. I can get it to work if it is not nested in the while loop however with the while loop it's continues to ask for the incorrect word. What am I missing? Here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
//Step 1: open file and declare variables//
FILE *fp;
fp = fopen("secretwords.txt","r");
char guess[20];
char secret[20];
int i;
//Step 2: Check that file opened correctly, terminate if not//
if (fp == NULL)
{
printf("Error reading file\n");
exit (0);
fclose(fp);
}
//Step 3: Create loop to run for each word to run to end of file//
while(fscanf(fp,"%s", secret)!=EOF)
{
for (i=0; i < 3; i++)
{
printf("Please guess the word: \n");
scanf("%s", guess);
if (strcmp(secret,guess)==0)
{
printf("Your guess was correct\n");
break;
}
else
{
printf("Your guess was incorrect. Please try again\n");
}
}
}
return 0;
}
When you do break, you break from the for loop, but not from the while loop.
To solve it, you can either change the design to have one loop only, or you should have the break instruction in the outer loop too.
You did not do break in the following part:
else
{
if(i == 2)
break;
printf("Your guess was incorrect. Please try again\n");
}
Hint: if the user has had 3 misses, the value of i after the for loop will equal to 3. This is your chance to do something (terminate the program).

Comparing user input with text file and looping in C

I'm creating a program that asks the user to input a word. The word is then compared with a word in a text file. If correct, I want the user to input another word which should correspond with the next word in the text file and this should loop until the end of the file. I'm having trouble with the loop to the end of the file. Could someone please review my code and give me a few pointers? thanks so much
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
//Step 1: open file and declare variables//
FILE *fp;
fp = fopen("secretwords.txt","r");
char guess[20];
char secret[20];
int i, count;
//Step 2: Check that file opened correctly, terminate if not//
if (fp == NULL)
{
printf("Error reading file\n");
exit (0);
fclose(fp);
}
//Step 3: Create loop to run for each word to run to end of file//
fscanf(fp,"%s", secret);
//Need to create a loop here that will read the text file 20 times,
// each time reading the next word//
for (i=0; i < 3; i++)
{
printf("Please guess the word: \n");
scanf("%s", guess);
if (strcmp(secret,guess)==0)
{
printf("Your guess was correct\n");
return 0; //This return will terminate the program.
// I need to restart loop from here
}
else
{
printf("Your guess was incorrect. Please try again\n");
}
}
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE *fp = fopen("secretwords.txt", "r");
if (fp == NULL)
{
printf("Error reading file\n");
return 1;
}
char guess[20] = {0};
char secret[20] = {0};
while(fscanf(fp, "%s", secret) != EOF) // i would suggest you use 'fscanf_s("%s", guess);' instead if available
{
printf("Please guess the word: \n");
scanf("%s", guess); // i would suggest you use 'scanf_s("%s", guess);' instead if available
if (!strncmp(secret, guess, sizeof(guess)))
{
printf("Your guess was correct. Continue ...\n");
}
else
{
printf("Your guess was incorrect. Good bye.\n");
break;
}
}
fclose(fp);
return 0;
}
i made some suggestions about scanf_s and fscanf_s, if they are available, use them. But still, i am wondering why they are still teaching bad code in schools? I would not suggest to use *scanf* functions at all. Further reading: uncontrolled format string
Move the fscanf call that reads from the file to a function that returns the next word
loop for user input, only calling the function outlined above when you need to advance to the next word in the file (when the user inputs the correct thing)

Resources