I have the following piece of code:
#include <stdio.h>
#include <stdlib.h>
int main (){
int s1 = 0;
int s2 = 0;
int frstEscolha;
do{
printf("\n\n WELCOME \n\n");
printf(" 1- JOGAR \n");
printf(" 2- SAIR \n");
scanf ("%d", &frstEscolha);
printf ("%d %d",s1,s2);
switch (frstEscolha) {
system ("cls");
int sndEscolha;
case (1):
s1 = 1;
printf ("\n\n NUMBER OF PLAYERS \n\n");
printf ("1- ONE PLAYER \n");
printf ("2- TWO PLAYERS \n");
scanf ("%d", & sndEscolha);
system ("cls");
do{
switch (sndEscolha) {
char *trdENome , *trdENome1, *trdENome2;
case (1):
s2 = 1;
printf ("\nPLAYER NAME: \n");
scanf ("%s", &trdENome);
printf("\nGOOD GAME %s \n\n", &trdENome);
case (2):
s2 = 1;
printf ("\nPLAYER 1 NAME \n");
scanf ("%s", &trdENome1);
printf ("\nPLAYER 2 NAME \n");
scanf ("%s", &trdENome2);
printf("\nGOOD GAME %s e %s \n\n", &trdENome1, &trdENome2);
default :
printf ("Invalid character, try again!!");
s2 = 0;
}
}
while (s2==0);
case (2): exit (0);
default :
printf ("Invalid character, try again!!");
s1 = 0;
}
}
while (s1 == 0);
return 0;
}
This is supposed to print a menu and let you choose your options to navigate the different menus, the while is used for repeating the process when the character inserted is not valid, but when this happens the console starts flickering and the program chrashes. How is this caused, and how can i fix it?
Thanks
After running your code, nothing seems to flicker uncontrollably and the program runs perfectly fine. Nothing crashes or bugs. The only problem in your code is your switch statement. They end up in an infinite loop. What I recommend is to put a break; at the end of each case to get out of that loop. Other than that, your code seems to run fine.
The following code is only to fix the infinite loop problem in the switch statement
case(1):
//your code here
break;
I believed I found the error to your code. In you brief description regarding your problem, I happened to find the error. In you first scanf, if the user inputs a character, the program breaks. My compiler kept on repeating the question.
What I recommend is to use if/else loops to solve your problem. Another solution is to change int frstEscolha to unsigned int frstEscolha. If the user happens to input a char, it could the value for a character without breaking the program. But highly recommend using if/else in this case.
If you are using unsigned int, the scan works like this.
scanf("%lf", &varName);
Related
i am pretty new to c, i m trying to make the user input a number, but if they input a letter or word it shows a warning and asks for input again, my code works fine if the user puts in a number but it goes into an infinite loop if the user inputs something invalid, here is my code
#include <stdio.h>
int main(void) {
float salary;
int status = 0;
while (status == 0)
{
printf(" Please input your yearly salary to calculate taxes: \n");
status = scanf(" %f", &salary);
if (status == 0)
printf("invalid input!\n");
}
printf("%.2f\n", salary);
return 0;
}
i thought that i was something to do with the buffer left over from the first scanf , but adding a space " %f" didnt work, i tried using fflush(stdin) after then scanf also didnt work. i m not sure what else i can try.
thanks in advance for any help.
You need to clear the buffer or it will keep evaluating it and cause the endless loop. Add one line after your invalid input: scanf("%*[^\n]")
#include <stdio.h>
int main(void) {
float salary;
int status = 0;
while (status == 0)
{
printf(" Please input your yearly salary to calculate taxes: \n");
status = scanf(" %f", &salary);
if (status == 0)
printf("invalid input!\n");
scanf("%*[^\n]");
}
printf("%.2f\n", salary);
return 0;
}
This will work. You can see a better explanation here: Scanf and loops
The problem is that scanf won't advance the file stream. You ask it to read a floating point value and it isn't able to, so it doesn't consume the input.
For example, let's say your input is "foo", which isn't a number. Your scanf call isn't able to successfully read anything and returns 0. Then, in the next iteration, "foo" is still waiting to be read from stdin.
Try changing your if condition to something like
if (status == 0) {
char foo[256];
fgets(foo, sizeof(foo), stdin);
printf("Invalid input! Expected a nmuber, got: %s", foo);
}
Notice how the entire input is read from stdin by the gets call.
Im having some problems making my newly started project to work (also im a beginner).
For some reason option number 4 in my interactive menu doesn't work and just takes a default route (doesn't output whats inside a file (file directory is fine.).
At this point i've read every forum searching for answer but couldn't modify my code in any way that would work.
So I decided to ask you for help.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#define kFileLocation "/Users/patrykpiwowarczyk/Desktop/STUDIA/FoCP/Kodowanie/TestProjektSemestralnyAngielski/TestProjektSemestralnyAngielski/authors.txt"
void options();
void start(void);
void score(void);
void optionz(void);
void author(void);
void pexit(void);
int main(void)
{
char ch;
int num;
char option;
while (1) {
printf("****Your English Learning Index Cards****\n\n");
printf("Enter 1-5 of the following options: \n\n");
options();
scanf("%c", &option);
switch (option) {
case '1':
break;
case '2':
break;
case '3':
break;
case '4':
author();
break;
case '5':
pexit();
break;
default:
printf("Please insert number ranging from 1-5 though... No cheating! \n\n");
printf("Press ENTER key to Continue\n");
}
}
return 0;
}
void options()
{
printf("1. Start Game \n");
printf("2. View Scoreboard \n");
printf("3. Options \n");
printf("4. Author \n");
printf("5. Exit \n\n");
}
void author()
{
char c;
FILE *authorsFile;
if ((authorsFile = fopen("/Users/patrykpiwowarczyk/Desktop/STUDIA/FoCP/Kodowanie/TestProjektSemestralnyAngielski/TestProjektSemestralnyAngielski/authors.txt","r")) == NULL)
{
printf("FAILED to read the file, maybe check directory?\n");
exit(1);
}
while ((c = fgetc(authorsFile)) != EOF)
{
printf("%c", c);
}
fclose(authorsFile);
}
void pexit()
{
puts("Your progress has been saved, see you next time.");
exit(0);
}
if you could help me in any way I would appreciate it soo much..
Greetings, Patryk Piwowarczyk.
PS: the #define kFileLocation is a leftover from my other tries. Omit it.
Based on your comments, I conclude the following:
The problem was that scanf correctly wrote the digit into the variable option the first time it was called. However, the second time scanf was called, it immediately returned the newline character from the previous menu selection, instead of waiting for the user to enter another digit. Whenever scanf returned a newline, the default case was triggered.
Therefore, the problem can be best solved by changing the scanf call to the following:
scanf(" %c", &option);
By adding a space to the start of the format string, you instruct scanf to discard all whitespace characters before reading the character. That way, you can insure that a newline will never be written into the option variable.
The problem of scanf reading newline characters instead of discarding them has been discussed in more detail in this question.
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!
#include <stdio.h>
void load_menu(void);
int main(void)
{
load_menu();
return 0;
}
void load_menu(void)
{
int choice;
int loopagain;
do
{
printf("Menu \n\n");
printf("Please enter your choice: \n");
printf("1. \n");
printf("2.\n");
printf("3.\n");
printf("4. Exit\n");
if (scanf("%d",&choice)==1)
{
switch(choice)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4: printf("Quitting program!\n");
break;
default: printf("Invalid choice! Please try again\n");
printf("\n");
break;
}
}
else
{
printf("Characters are invalid, please enter a number: \n ");
if (scanf("%d",&loopagain)==1)
load_menu();
}
}while((choice !=4));
}
why is this still giving me an infinite loop when I enter a character? It is a menu (the case statements still need to be filled) but i am taking care of the character input by the if statement but it still does not seem to work. Thanks
If the character input is invalid, the loopagain in the newly-called load_menu() won’t be the same as in its caller. Don’t recurse at all:
else
{
printf("Characters are invalid, please enter a number: \n ");
choice = 0; // Unused, so continue the loop
}
I believe, aside from the problems identified so far, is that the offending "letter" is stuck in the input buffer. When reading a number with scanf, it stops as soon as it hits anything not whitespade and not a digit. So if the buffer contains "a\n", and we call scanf("%d", ...), then scanf will return immediatelty, and will keep on doing so until the offening 'a' has been removed from the buffer.
What we need is a little loop to remove the offending "rubbish" from the input buffer.
Here's that question asked before (although the flushing is for a slightly different reason, the solution is the same):
Question about flushing buffer
After you enter something the is not a digit, and as such is not accepted by scanf("%d",&choice) the input buffer is not flushed. I believe you should be able to fix this issues with a call to fflush(stdin) when handling unacceptable inputs. Better, you would probably be better servde to flush the input buffer after each time you call scanf.
To my mind, your handling of an incorrect input doesn't make sense. It should be handled more like your default: case, I think. The recursive call, as has been stated by others, doesn't make sense, nor does calling scanf again for input when you are about to go back to displaying the menu and getting user input yet again.
I think your problem is the loopagain variable. By the name, you were thinking about this variable like a flag to loop or not again and to manage the way your second loop would go. Since you are reading it from stdin(scanf) you'll lost the control over it.
Since you already have one scanf in your implementation and since it is a loop, you won't need recursive calls and you can use always the same scanf, using the loopagain variable/flag in the proper way.
Even better is that in this way, there's no char wich its integer value is 4(it woul never pass the scanf test with value 1, but still...) besides the EOT (ascii - cntr-D) wich is a non-common one, and you can think of it as an alternative way to break your program.
One soluiton is this(I guess, by my interpretation) :
#include <stdio.h>
void load_menu(void);
int main(void)
{
load_menu();
return 0;
}
void load_menu(void)
{
int choice;
int loopagain = 1;
do
{
if(loopagain != 0){ /*You'll set it to different from 0 if the user entered a 'bad' number so the menu is only printed once*/
printf("Menu \n\n");
printf("Please enter your choice: \n");
printf("1. \n");
printf("2.\n");
printf("3.\n");
printf("4. Exit\n");
}
if (scanf("%d",&choice)==1)
{
switch(choice)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4: printf("Quitting program!\n");
break;
default:printf("Invalid choice! Please try again\n");
loopagain = 0;
printf("\n");
break;
}
}else{
printf("Characters are invalid, please enter a number: \n ");
loopagain = 0;
}
}while(choice !=4);
}
Hope it helped.
In the code below in lesson2() i have used a password to enter the function but when i enter the function it does not takes in the passord and says incorrect password.By not taking in the password,i mean to say that i have used gets but its waiting for me to input a password.please dont tell me not to use gets!
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<dos.h>
int mistakes=0,mistakes_length,len;
char temp[100];
void lesson1(void);
void lesson2(void);
void result(void);
void main(void)
{
int choice;
clrscr();
printf("Enter a lesson number to practise:1-10 \n");
scanf("%d",&choice);
switch(choice)
{
case 1:
lesson1();
result();
break;
case 2:
lesson2();
result();
break;
default:
printf("You did not entered a valid choice program quitting..\n");
exit(0);
}
getch();
}
void lesson1(void)
{
int i;
char str1[100]="testing the typing tutor if it works";
mistakes_length=5;
clrscr();
gotoxy(25,2);
puts("Welcome to lesson 1");
puts(str1);
len=strlen(str1);
for(i=0;i<len;i++)
{
temp[i]=getche();
if(strncmpi(&str1[i],&temp[i],1))//does not match
{
mistakes++;
sound(100);
delay(1000);
nosound();
}
}
getch();
}
void result(void)
{
printf("Your statsistics are as under:\nYou performed this lesson with %d mistakes\n",mistakes);
if(mistakes>=mistakes_length)
{
printf("\n Your typing is very bad");//allow anything to be typed with any mistake in lesson 1
}
if(mistakes>3&&mistakes<5)
{
printf("Bad!,You need to practise this excercise more\n");
}
if(mistakes>=1&&mistakes<=3)
{
printf("Good!you can still do better\n");
}
if(mistakes==0)
{
printf("Excellent!You are qualified for the next lesson\n");
printf("The next lessons password is \n\t\t\t:12345");
}
}
void lesson2(void)
{
char password[]="12345",str2[]="My name is khan and i am not a criminal";
int i;
mistakes=0,mistakes_length=0,
printf("Enter password:\n");
gets(temp);
if(strcmp(temp,password))
{
gotoxy(20,25);
printf("Wrong Password,Program Quitting.\n");
getch();
exit(1);
}
gotoxy(25,25);
printf("Password Accpted!");
getch();
clrscr();
gotoxy(25,2);
printf("Welcome to lesson 2\n");
printf("Type the text shown below:\n");
puts(str2);
len=strlen(str2);
for(i=0;i<len;i++)
{
temp[i]=getche();
if(strncmp(&str2[i],&temp[i],1));
{
mistakes++;
}
}
getch();
}
I think that it is the scanf and gets together making a problem!
Your problem is that prior to calling gets(), you have called scanf("%d",&choice); (in main()). The problem with this is that console input is line oriented. This means that although you are only waiting for a number to be entered the user has to enter a complete line ending in newline. The %d format specifier only consumes the digit characters leaving the rest of the line in the buffer to be used by the next console input call; which in this case is gets() which sees the newline in the buffer and returns an empty string without waiting for further input.
A solution:
scanf("%d",&choice);
while(getchar() != '\n' ) { /*no nothing*/}
I think the problem you are seeing is in fact coming from the main method.
The scanf() call that you make is only looking for "%d" rather than "%d\n".
Therefore, you enter the number 2 in order to try test 2, and must press enter before that value gets to the program. Since scanf is not trying to match it, that newline remains as part of the input stream and thus is passed directly to gets() within the next function.
Therefore, if you change the string within scanf inside the main function, you should see the code start working.
Now on another note (and I know that you asked us not to but...) you really shouldn't use gets(). In order to switch to fgets, just replace gets(temp) with fgets(temp,99,stdin). That 99 is any number that is less than the size of the temp buffer you have made, which in this case has size 100.
Try printing temp like this: printf("[%s]\n", temp); after the gets(temp); to see what is saved in temp. It may takes as input a previous given input from lesson1 function?
If this is the case, something like this maybe will fix the problem:
char other_tmp[5];
gets(other_tmp);
gets(temp);
although in such a case you should better correct the lesson1 function instead.
it supposed to work.
edit your code:
int r = gets(temp);
printf("returned: %d, Entered: %s\n", r, temp);
and post here the result