Issue with a nested for loop - c

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

Related

reading inputs from input file, keep getting infinite loop

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

Program not asking for new entry if you enter invalid choice in String format

I'm having a problem understanding how to get my while loop to simply output a message saying "Invalid Input" and asking for a new question from the user unless he chooses number 1 or 2 in the list. What happens if you for example input : asdas instead of a integer the program never stops looping.
What I would like to happen is for the program to tell the user to enter a new number from 1-2 instead of simply stopping running which i can achieve by setting the default in the switch to exit(0); or runSystem = false;
For example:
CMD Says enter 1-2 the user enters : asdaf (never stops looping) as in current situation.
What I want is: asdf and then it says "enter a new choice" and waits for a correct answer.
What bothers me is the fact that the program will do as i want it to if you enter an invalid number for example: 12312312 and ask for a new entry but it doesn't work with string input.
Code:
#include <stdio.h>
#include <stdbool.h>
int main(int argc, char **argv) {
int userinput;
int runSystem = true;
void options() {
printf("<========Welcome to the program, please make a choice========> \n\n");
printf("1: Say Hello\n");
printf("2: Say GoodBye\n");
printf("Please enter a choice:");
scanf("%d", &userinput);
}
while (runSystem) {
options();
switch(userinput) {
case 1: printf("Hello!\n");
break;
case 2: printf("GoodBye!\n");
break;
case 3: printf("Invalid, try again\n");
break;
default:
break;
}
}
return 0;
}
scanf("%d", &userinput); expects an int as the input. When you give a non-integer, scanf() won't assign it to userinput.
Check the return value of scanf() to see if it was successful. It returns the number of successful assignments it did.
When you give a string as input, scanf() won't accept it and will leave it in the input buffer unconsumed.
When you do scanf() again, the invalid input is still present in the input buffer and that is what the second scanf() tries to read. The same thing happens and this goes on. This is the reason behind your infinite loop.
To overcome this, you should consume the invalid input from the input buffer after displaying the message in case 3. Do something like
int ch;
while( (ch=getchar())!='\n' && ch!=EOF );
This will consume from the input buffer till a \n is encountered. getchar() return EOF on failure.
Edit: Standard C doesn't allow nested function definitions. The reason why you didn't get an error for that is probably because your compiler allows this as an extension. But it may not work for other compilers.
See this and this.
You could place the definition of options() within the while loop calling it or get the value for userinput as a return value or via a pointer to the variable passed to the function.
Valid C compiler does not allow declaration of the function options inside the main.
Make that function returning your input and pass the returning value to the switch. Also in order to stop the while loop case 2: should change the runSystem to false;
input : asdas instead of a integer the program never stops looping.
This is because when scanf("%d", &userinput); failed it did not updated the variable userinput.
Check the standard 7.21.6.4 The scanf function.
You can read about behaviour of scanf
here.
On success, the scanf returns the number of items successfully read. This count can match the expected number of readings or fewer, even zero, if a matching failure happens. In the case of an input failure before any data could be successfully read, EOF is returned.
Knowing that you can check the return value of scanf and make appropriate decision. Presented solution eats the bad characters.
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
int options(void) {
int c;
int ret;
int x = 0;
int error = 0;
printf("<========Welcome to the program, please make a choice========> \n\n");
printf("1: Say Hello\n");
printf("2: Say GoodBye\n");
printf("Please enter a choice:");
while(1)
{
c = '0';
if(!error)
printf("Input a number:\n");
else
error = 0;
ret = scanf("%d", &x);
if(ret == EOF) {
return 2; // END OF PROGRAM
}
else
{
if (ret == 1){
return x;
}
else // NOT a number
{
printf("No letters! Input a number:\n");
do
{
c = getchar();
if(c == EOF)
return 2; // END OF PROGRAM
}
while (!isdigit(c) && c!='\n');
ungetc(c, stdin);
error = 1;
}
}
}
}
int main(void) {
int userinput;
int runSystem = true;
while (runSystem) {
userinput = options();
switch(userinput) {
case 1: printf("Hello!\n");
break;
case 2: printf("GoodBye!\n");
runSystem = false;
break;
default:
case 3: printf("Invalid, try again\n");
break;
}
}
return 0;
}
Output:
<========Welcome to the program, please make a choice========>
1: Say Hello
2: Say GoodBye
Please enter a choice:Input a number:
X
No letters! Input a number:
a
No letters! Input a number:
1
Hello!
<========Welcome to the program, please make a choice========>
1: Say Hello
2: Say GoodBye
Please enter a choice:Input a number:
7
Invalid, try again
<========Welcome to the program, please make a choice========>
1: Say Hello
2: Say GoodBye
Please enter a choice:Input a number:
2
GoodBye!

loop not working properly, also needing data validation

This may be a simple answer. I have only been programming with C for a month.
I am creating a C-program that the user is presented with a menu 1-4.
Menu options 1-3 ask the user for an integer, when an integer is input, the program writes or "draws" that amount of "dots" or periods.
Each of the first options will do the same function, but a while loop, do-while loop, and a for loop respectively.
The only way to terminate program is to select 4 at the main menu.
My question is how to get my program to loop back and continue to work properly.
When i execute the program it works correctly the first time, but when the program loops back to the main menu. No further options work. IE: if i try the input an integer again for the "dot drawing" it doesnt work correctly.
I am also Having trouble validating input on either menu for letters or "non numbers", at the moment if you input a letter it breaks the program.
Im not sure what to do and where to go with this.
Im not needing the code re-written, perhaps just some ideas of where to take it.
I'll accept any references or links provided.
a copy of my incomplete program is included below:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
system("cls");
int programRun=0;
int menuSelection=0;
int absmenuSelection=0;
int dotNumber=0;
int countNumber=0;
char enter;
while(programRun==0)
{
system("cls");
printf("\nplease make a number selection\n");
printf("Please select a choice:\n");
printf("[1] While loop...\n");
printf("[2] Do-While loop...\n");
printf("[3] For loop...\n");
printf("[4] Exit program...\n\n");
scanf("%d%c",&menuSelection,&enter);
absmenuSelection= abs(menuSelection);
if (absmenuSelection <1 || absmenuSelection>4)
{
}
switch (absmenuSelection)
{
case 1:
printf("\nPlease input a number for the amount of dots you wish to see...");
scanf("%d", &dotNumber);
if(dotNumber > 0)
{
while(countNumber<dotNumber)
{
countNumber++;
printf(".");
}
}
else{
printf("\nsorry, that is an invalid response. Now you have to try again.\n");
}
printf("\n");
system("pause");
break;
case 2:
printf("\nPlease input a number for the amount of dots you wish to see...");
scanf("%d", &dotNumber);
if(dotNumber > 0)
{
do
{
countNumber++;
printf(".",countNumber);
}
while( countNumber<dotNumber );
}
else
{
printf("\nsorry, that is an invalid response. Now you have to try again.\n");
}
printf("\n");
system("pause");
break;
case 3:
printf("\nPlease input a number for the amount of dots you wish to see...");
scanf("%d", &dotNumber);
if(dotNumber > 0)
{
for(countNumber=0;countNumber<dotNumber;countNumber++)
{
printf(".",countNumber + 1);
}
}
else
{
printf("\nsorry, that is an invalid response. Now you have to try again.\n");
}
printf("\n");
system("pause");
break;
case 4:
while(programRun>1)
programRun=1;
printf("\nOkay have a nice day");
return 0;
default:
printf("\nsorry that is an invalid statement, try again\n\n");
system("pause");
}}
system ("pause") ;
return 0;
}
its working well .....
Set after each case: countNumber=0;
or try
if(dotNumber > 0)
{
countNumber=0;
/*REST */
}
otherwise case 1: case 2: will not work if i try 2 times after giving dotNumber a higher value at first and lower at last
EDIT:
The C library function void isdigit(int c) checks if the passed character is a decimal digit character.
if( isdigit(variableHere) )
{
//is a digit
}
Sample o/p
please make a number selection
Please select a choice:
[1] While loop...
[2] Do-While loop...
[3] For loop...
[4] Exit program...
1
Please input a number for the amount of dots you wish to see 4
....
Press any key to continue . . .

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)

Compare user input with text file in C

I need to have a user input a word then compare the word with a text file to see if it is correct. The user has 3 attempts to enter the word before the program terminates. My issue is reading the word from the file I know it's something simple that I have wrong. I should also clarify that the error I'm getting is in the compiler I haven't gotten to the point of being able to compare the strings yet!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
fp = fopen("secret.txt","r");
char guess[10];
const char secret[10];
int i, c;
c = getc(fp);
fgets(secret, sizeof(secret), fp);
for (i=0; i < 3; i++)
{
printf("Please guess the word: \n");
scanf("%s", guess);
while (c !=EOF)
{
if (strcmp(secret,guess)==0)
{
printf("Your guess was correct");
return 0;
}
else
{
printf("Your guess was incorrect. Please try again\n");
}
}
fclose (fp);
}
return 0;
}
Here are some pointers:
c = getc(fp) consumes the first character of the file, so it never becomes part of the secret variable.
If secret.txt contains a newline, the newline is read into the secret variable.
The while (c != EOF) loop seems pointless, since c isn't modified inside the loop. Furthermore, the infinite nature of the loop prevents the outer for loop from functioning correctly.
If I were you, I'd fix the while loop and would make sure that secret is read correctly, for example by printing it out or examining it in a debugger.
What is
c = getc(fp);
needed for? My "guess" would be that you read the first character of the word into c and then secret misses the first character.
EDIT: Instead of using getc for EOF checking, which as said corrupts the read word (and this while loop is rubbish anyway), just check the return value of fgets:
if(fgets(secret, sizeof(secret), fp) == NULL)
//file is empty or other error occurred
and remove this infinite while(c != EOF) loop.
So it should rather look something like:
FILE *fp = fopen("secret.txt","r");
char guess[10];
const char secret[10];
int i;
if(fgets(secret, sizeof(secret), fp) == NULL)
{
printf("Error while reading file\n");
return -1;
}
fclose(fp);
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");
return 0;
}
else
printf("Your guess was incorrect. Please try again\n");
}
return 0;
Your code is grossly off: you do not alter 'c' inside a loop, making it spin indefinitely. It's a good idea to sketch your algorithm on a piece of paper before you start coding. In your case, pseudocode should look like this:
Open file
Read the secret
Close file
Repeat three times:
--- Display the prompt
--- Read user input
--- If user input matches the secret, congratulate the user and exit.
Tell the user his guess was incorrect.
At this point, converting it to C should be more or less mechanical. Good luck!
while (c !=EOF)
{
if (strcmp(secret,guess)==0)
{
printf("Your guess was correct");
return 0;
}
else
{
printf("Your guess was incorrect. Please try again\n");
}
}
looks like an infinite loop to me

Resources