Loop back to question instead of printing out "Try again"? (C) - c

this is my first day coding and I'm trying to see how the code work, how can I change Y/N to Yes/No and loop back questions if the answer is not Yes instead of printing out "Try again?" or make it better?
int main(void)
{
char answer;
int name;
printf("Enter Username: \n");
scanf("%s",&name);
printf("Is your username \"%s\"? Enter Y or N\n", &name);
while (scanf(" %c", &answer) == 1 && answer == 'Y')
{
char answer2;
Sleep(1000);
printf("Username confirmed\n");
Sleep(2000);
int pass;
printf("Enter your password: \n");
scanf("%s",&pass);
printf("Is your password \"%s\"? Enter Y or N\n", &pass);
while (scanf(" %c", &answer2) == 1 && answer2 == 'Y')
{
printf("Success!");
Sleep(1000);
exit;
}
printf("Try again..\n");
Sleep(1000);
exit;
}
Sleep(1000);
printf("Try again..\n");
Sleep(1000);
exit;
return 0;
}

My best advice, as Weather Vane told you in the comment section, is to try to compile your code, before making changes: you'll find out that it won't even compile, since there are some errors (https://godbolt.org/z/MdahM4sT8).
You should debug and try to figure out why it doesn't work, fix it, then move to the new "features".
You probably want to change the while() condition and read a sequence of characters (array of char) instead of a single char.
char answer[4];
while (scanf("%3s", answer) > 0 && strcmp(answer, "Yes") == 0)
char answer[4]; creates an array of characters (which can be called a string, even though C doesn't have that abstraction) of size 4.
You might want to know why we need a size of 4, since the longer answer we can get is "Yes". Well, a string in C is a sequence of characters (char), ending with a special character, called terminating character '\0'.
Therefore, when you read a string with scanf(), you need to reserve some space for the terminating character aswell, and scanf() will add it when reading a space or carriage return after your input string. So if you enter "Yes" and then press the Return key, your answer[4] buffer will look like: {'Y', 'e', 's', '\0'}.
%3s tells scanf() to read only the first 3 characters of the string (prevents security issues like buffer overflow).
int scanf(const char *format, ...)
Description
Reads formatted input from stdin.
Return Value
On success, the function returns the number of items of the argument list successfully read. If a reading error happens or the end-of-file is reached while reading, the proper indicator is set (feof or ferror) and, if either happens before any data could be successfully read, EOF is returned.
Once you've read that string, you can use strcmp(), a function defined in `<string.h> header, that takes in 2 string parameters, and returns:
a negative value if the first precedes alphabetically the second;
0 if they're equal;
a positive integer if the second precedes alphabetically the second;
Therefore you can check if strcmp(answer, "Yes") == 0 to know if you've read Yes, and

Related

Generating a dice game - C Programming

I'm following a tutorial on youtube and was doing a dice generator.
It basically print out 3 dice result and sum out the dice result.
After which, the user will look at the sum, and based on the sum, the user going to guess whether the next roll is going to be higher,lower, or the same.
Below is my code, suppose, when I typed 'yes', it should be doing the code inside the if statement. However, it went straight to the else statement. Can someone please tell me what's wrong?
int answer;
int guess;
int diceRoll4 = 0;
printf("Would you like to guess your next dice? Y/N \n");
scanf(" %c", &answer);
if (answer == 'yes' ){
printf("What is your guess?\n");
printf("please key in your number \n");
scanf(" %d", &guess);
if (guess > diceRoll4 ){
printf(" You got it wrong, too high!");
}
else if (guess < diceRoll4){
printf(" You got it wrong, too low!");
}
else {
printf("You got it right");
}
}
else{
printf("Thanks for playing");
}
First of all, answer should be an array of chars in order to hold a string. Change
int answer;
to
char answer[10]; //Or any other reasonable size
Secondly, since you want to scan a string and not a character, change
scanf(" %c", &answer);
to
scanf("%9s", answer);
The 9 will scan a maximum of 9 characters (+1 for the NUL-terminator at the end), thus preventing buffer overflows.
I've removed & as %s expects a char* while &answer will give a char(*)[10]. Name of an array gets converted into a pointer to its first element char*, exactly what %s expects. The above scanf is thus equivalent to
scanf("%9s", &answer[0]);
Thirdly, comparing two strings using == compares pointers and not the actual content in them. Use strcmp from string.h instead. It returns 0 when both its arguments hold the same content. Change
if (answer == 'yes' ){
to
if (strcmp(answer, "yes") == 0){
Double quotes are used to denote a NUL-terminated string(char*), which is exactly what strcmp expects, while single quotes, as in your code, is a multi-character literal whose value is implementation-defined.
'yes' is a multi-byte character whose behaviour is implementation-defined.
What you probably want is to read and compare a single char:
if (answer == 'y' ){
or read a whole string and compare:
char answer[128];
scanf("%s", answer);
if ( strcmp(answer,"yes") == 0 ){
...
}
Notice that I changed the type of answer and used %s to read a string.
If you do not want to read in a string, but only a single char where the user can answer either Y or N, you should change int answer; to char answer;. You can then go on using your original scanf()-call. You will still need to change
if (answer == 'yes')
to
if (answer == 'Y')
If you want the user to either type in y or Y you could user toupper() from ctype.h and change your if-condition to if (toupper(answer) == 'Y').
To test the equality you have to use strcmp. If the returning value is 0 it means that they are equal.
if (strcmp(answer, "yes") == 0) {
// ...
} else {
// ...
}
Notes:
Using just answer == 'yes' it test the equality of pointers not value. This is the reason why enters only in else.
Because answer is int you have to change to an array
char answer[15]
As #Sathya mentioned you are reading just a char %c for reading a string you have to use %s
scanf("%s", answer);
Instead of 'yes' which is multi-character character constant change to "yes" that is an array of char with \0 at the end, more informations here.
this line:
if (answer == 'yes' ){
has several problems.
1) the definition of 'answer' is 'int' but the scanf is inputting a single character
2) answer could be compared with 'y' or 'n' but not to a array of char.
3) since the scanf only input a single char
and you/the user input 'yes',
only the first character was consumed,
so the 'es' are still in the input buffer
4) note the the single character could be anything, except white space.
the leading space in the format string would consume any white space.
so the user could input say 'y' or 'Y'
these are different characters
however, using the toupper() macro from ctypes.h
would mean only a 'Y' would need to be compared
5) if you decide to read a string,
then 'answer' needs to be a character array,
say: char answer[10];
and the scanf needs to have a max length modifier
on the associated "%s" input/conversion parameter
so as to avoid the user overflowing the input buffer
and the comparison would be via the strcmp() function
6) always check the returned value (not the parameter value)
from scanf to assure the operation was successful
7) diceRoll4 and guess can never be a negative number
so the variable definitions should be unsigned
and the associated scanf() for guess should use
something like "%u"
8) on the printf() format strings, always end them with '\n'
so the sting will be immediately displayed to the user,
otherwise, they will only be displayed
when a input statement is executed or the program exits

Don't understand how to input/print and compare string in loop in C

I'm newcomer to C and I am stuck. I want to write simple program, which will take input from keyboard and output it if it isn't an 'exit' word. I've tried few different approaches and none of them works. Almost in all cases I get infinite output of the first input.
Here is one of my approaches:
#include <stdio.h>
int main() {
char word[80];
while (1) {
puts("Enter a string: ");
scanf("%79[^\n]", word);
if (word == "exit")
break;
printf("You have typed %s", word);
}
return 0;
}
I thought after it finish every loop it should give me prompt again, but it doesn't.
What I am doing wrong.
Please if you know give me some advice.
Thanks in advance. Really, guys I will be so happy if you help me to understand what I am doing wrong.
Oh, by the way I've noticed that when I typed some word and press 'Enter', the result string also include Enter at the end. How can I get rid of this ?
Improper string compare - use strcmp().
if (word == "exit") simply compares 2 address: the address of the first char in word and the address of the first char in string literal "exit". Code needs to compare the content beginning at those addresses: strcmp() does that.
Left-over '\n' from the previous line's Enter. Add a space to scanf() format to consume optional leading white-space. Also check scanf() results.
scanf() specifiers like "%d", "%u" and "%f" by themselves consume optional leading white-space. 3 exceptions: "%c", "%n" and "%[".
Add '\n' at end of printf() format. # Matt McNabb
#include <stdio.h>
int main() {
char word[80];
while (1) {
puts("Enter a string: ");
// v space added here
if (scanf(" %79[^\n]", word) != 1)
break; // Nothing saved into word or EOF or I/O Error
if (strcmp(word, "exit") == 0)
break;
printf("You have typed %s\n", word);
}
return 0;
}
Nice that OP used a proper width limited value of 79 in scanf()
Oh, by the way I've noticed that when I typed some word and press 'Enter', the result string also include Enter at the end. How can I get rid of this ?
This is because you don't output a newline after printf("You have typed %s", word);. The next statement executed is puts("Enter a string: "); . So you will see You have typed helloEnter a string:. To fix this, change to printf("You have typed %s\n", word);
As others have mentioned, use strcmp to compare strings in C.
Finally, the scanf format string "%79[^\n]" does not match a newline. So the input stream still contains a newline. Next time you reach this statement the newline is still in the stream , and it still doesn't match because you specifically excluded newlines.
You will need to discard that newline (and any other input on the line) before getting the next line. One way to do that is to change the input to scanf("%79[^\n]%*[^\n]", word); getchar(); That means:
Read up to 79 non-newlines
Read all the non-newline things , and don't store them
Read a character (which must be a newline now) and don't store it
Finally it would be a good idea to check the return value of scanf so that if there is an error then you can exit your program instead of going into an infinite loop.
The specifier [^\n] will abort scanf if the next character is a newline (\n), without reading the newline. Because of that, the scanf calls after the first one won't read any input.
If you want to read single words, use the %79s specifier and the following code to remove the \n at the end of your string:
if(word[strlen(word)]=='\n')
word[strlen(word)]='\0';
If you want to read whole lines, you can remove the newline from the input buffer this way:
char line[80];
int i;
while(1)
{
puts("Enter a string:");
i=-1;
scanf("%79[^\n]%n",line,&i);
//%n returns the number of characters read so far by the scanf call
//if scanf encounters a newline, it will abort and won't modify i
if(i==-1)
getchar(); //removes the newline from the input buffer
if(strcmp(line,"exit")==0)
break;
printf("You have typed %s\n",line);
}
return 0;
It is better to clear (to have a reproducible content) with memset(3) the memory buffer before reading it, and you should use strcmp(3) to compare strings. Also, consider using fflush(3) before input (even if it is not actually necessary in your case), don't forget to test result of scanf(3), also most printf(3) format control strings should end with a \n -for end-of-line with flushing- so:
#include <stdio.h>
int main() {
char word[80];
while(1) {
puts("Enter a string: ");
memset (word, 0, sizeof(word)); // not strictly necessary
fflush(stdout); // not strictly necessary
if (scanf("%79[^\n]", word)<=0) exit(EXIT_FAILURE);
if (!strcmp(word,"exit"))
break;
printf("You have typed %s\n", word);
};
return 0;
}
I would suggest reading a whole line with fgets(3) and getting rid of its ending newline (using strchr(3)). Also read about getline(3)
Don't forget to compile with all warnings and debug info (e.g. gcc -Wall -g) and learn how to use the debugger (e.g. gdb)
Your first problem is that you can't compare a string with '=='. So:
if (word == "exit")
should be
if ( strncmp( word, "exit", 4 ) == 0 )
(You could also use strncmp( word, "exit", strlen(word) ) if you know that word is zero-terminated and safe from bad values. There's a few other options also.)
Your second problem is that scanf() is not consuming the input, probably because it's not matching what you've told it to expect. Here is a good explanation of how to do what you want to do:
http://home.datacomm.ch/t_wolf/tw/c/getting_input.html

How Does Char Variable Work in C

What I am trying to accomplish is prompting the user with the question of do they want to run the program again. They either type y or n. If y, it reruns the program. If no, it stops the program. Anything other than those two will prompt an error and ask the question again. I'm used to C# where strings are not complicated, but in C, I guess there technically isn't strings, so we have to use either char arrays or char pointers. I've tried both, none that work that way I want, but I'm probably the problem. This is what I have.
char answer[1] = "a";
while (strcmp(answer, "y") != 0 || strcmp(answer, "n") != 0)
{
printf ("\n\nWould you like to run the program again? Type y or n. Then, hit Enter.");
scanf ("%c", answer);
if (strcmp(answer, "y") == 0)
{
main();
}
else if (strcmp(answer, "n") == 0)
{
continue;
}
else
{
printf ("\nERROR: Invalid input was provided. Your answer must be either y or n. Hit Enter to continue.");
F = getchar();
while ((getchar()) != F && EOF != '\n');
}
}
I have other while loops similar to this that work as expected, but use a float. So I'm assuming the problem is me using char here. What happens right now is that it doesn't even prompt the user for the question. It just asks the question and shows the error right afterwards. I'm sure there are other things wrong with this code, but since I can't get the prompt to work, I cannot test the rest of it yet.
I suggest using a light weight getchar() instead of the heavy scanf.
#include <stdio.h>
int c; /* Note getchar returns int because it must handle EOF as well. */
for (;;) {
printf ("Enter y or n\n");
c = getchar();
switch (c) {
case 'y': ...
break;
case 'n': ...
break:
case EOF:
exit(0);
}
}
"a" is a string literal == char id[2]={'a','\0'} //Strings are
char arrays terminated by zero, in C
'a' is a char literal
strcmp is just "compare each char in two strings, until you hit '\0'"
scanf ("%c", ___); expect an address to write to as the second
argument. Functions in C cannot modify their arguments (they don't
have access to them--they get their own local copy) unless they have
a memory address. You need to put &answer in there.
Jens has already basically answered the question, you most likely want to use getchar so that you can detect EOF easily. Unlike scanf("%c",...), getchar will not skip spaces, and I believe both versions will leave you with the unprocessed rest of the input line (a newline character ('\n') at least) after each getchar. You might want to something like
int dump;
while((dump=getchar())!='\n' && dump!=EOF) {};
So that you discard the rest of the line once you've read your first character of it.
Otherwise, the next getchar will get the next unprocessed character of the same line. ('\n' if the line was a single letter).
Here is one way to do it. It is by no means the only way to do it, but I think it accomplishes what you want. You should not call the main function recursively.
#include <stdio.h>
#include <stdlib.h>
void run_program()
{
printf("program was run.");
}
int main() {
char answer[2] = "y\0";
int dump;
do {
if (answer[0] == 'y')
{
run_program(); /* Not main, don't call main recursively. */
}
printf ("\n\nWould you like to run the program again? Type y or n. Then, hit Enter.\n");
scanf ("%1s", answer);
/* Dump all other characters on the input buffer to
prevent continuous reading old characters if a user
types more than one, as suggested by ThorX89. */
while((dump=getchar())!='\n' && dump!=EOF);
if (answer[0] != 'n' && answer[0] != 'y')
{
printf ("Please enter either y or n\n");
}
} while (answer[0] != 'n');
return 0;
}
Using %s instead of %c, reads in the new line so that the new line character is not in the stdin buffer which would become answer then next time scanf was called.
The run_program function is just a function where you would put your program's logic. You can call it whatever you want. I did this to separate out the menu logic from the logic of the actual program.
Well, you are comparing two strings instead of characters.
If you want to compare two character you have to follow this syntax:
char c;
scanf("%c",&c);
if(c == 'y')
//do something
else
//do nothing

Why does this if condition not work even if I enter the correct data?

#include < stdio.h >
#include < process.h >
rec();
main() {
int a, fact;
char question, n, y;
do {
printf("\nEnter any number ");
scanf("%d", & a);
fact = rec(a);
printf("Factorial value = %d\n", fact);
printf("do you want to exit.....(y/n):");
scanf("%s", & question);
}
while (question == n);
exit(0);
}
rec(int x) {
int f;
if (x == 1) return 1;
else f = x * rec(x - 1);
return f;
}
In this program I want to get factorial of the entered number, which I get. But I also want the user to say whether to exit or get the factorial of another number, which I can't do. It asks user but when I enter "n" it exits.
Where is the error?
You want
while (question == 'n');
Or
char question, n = 'n', y = 'y';
Though I find the 2nd version a little redundant.
Either way you need to change
scanf("%s"
to
scanf("%c"
To correctly read in a single char and not a string. Thanks RageD
One problem is the combination of:
char question, n, y;
scanf("%s", &question);
You are using %s to read a null-terminated string into a single character. Even if you hit 'y' and return, you'll be overwriting beyond the end of the variable. This is not good. (The good news is that "%s" skips over white space, including the newline after the number).
You either need to use "%c" in the format:
char question;
scanf(" %c", &question); // NB: The leading space is important!
or you need to use a string format and a string variable (and no &):
char question[10];
scanf("%9s", question);
If you use an array, you need to consider whether to use strcmp(), or whether to compare the first character from the input:
while (strcmp(question, "n") == 0);
while (question[0] == 'n');
You probably got told by the compiler that you'd not declared variable n so you added it. You probably need the loop to end with while (question == 'n');and then get rid of the (now) unused variablen(and the currently unused variabley`).
Note that if you use omit the space in the " %c" format string:
scanf("%c", &question);
then it will normally get the newline after the number, which won't be 'n', so your loop will exit every time, apparently without waiting for you to enter anything. You can finesse that with scanf(" %c", &question); which skips white space before reading a character.
You should test that scanf() received the input you expected each time you use it. The correct test for single item inputs is:
if (scanf(" %c", &question) != 1)
...input failed...
If you need to distinguish between EOF and conversion failure, you can capture the return from scanf():
int rc;
if ((rc = scanf(" %c", &question)) != 1)
...rc == EOF on EOF; rc == 0 on 'conversion failure'...
...a single character input can't easily fail...
...but if someone types 'a' instead of '9' when you're looking for a number...
Getting I/O right using scanf() is distressingly hard. Many experienced programmers simply don't use it; it is too hard to get right. Instead, we use fgets() or POSIX getline() to read a line of data, and then use sscanf() to parse it. There are many advantages to this, but a primary one is that the newline has been eaten so you don't run into problems with the variable question not containing the answer you expect.

How to terminate a loop when a letter entered in C?

In my task I need to use a loop and get an input between 1-5, if i get any other input i need to keep iterating until i get 1-5.
Could you please tell me what am i doing wrong?
Part of my code:
int rateSelected, weeklyHours;
printf("Enter the number corresponding to the desired pay rate or action:\n");
printf("1) %.2lf$/hr 2) %.2lf$/hr\n", RATE1, RATE2);
printf("3) %.2lf$/hr 4) %.2lf$/hr\n", RATE3, RATE4);
printf("5) Quit\n");
while ((scanf("%d", &rateSelected)) != EOF && rateSelected != 5)
{
if (rateSelected > 5 || isalpha(rateSelected) ==1){
printf("please enter a number between 1-5:\n");
continue;
}
printf("Now enter your weekly hours:\n");
scanf("%d", &weeklyHours);
ChoosePayRate(rateSelected, weeklyHours);
}
tnx
The problem is your use of %d format specifier. When letters are entered instead of digits, scanf returns zero to indicate that nothing is read. If you would like to allow entering letters along with digits, you should either add a read of a string when scanf returns zero, or always read into a string buffer, and then use sscanf or atoi to convert the string to integer.
You better use fgets() and strtol() for this. Scanf and the line-buffering of stdio is not very helpful together...
char line[LINE_MAX];
do {
fgets(line, sizeof(line), stdin);
} while(!isdigit(line[0]));
int choice = strtol(line, NULL, 10);
isalpha(rateselected) will never be true because you are storing an int in rateselected.
scanf("%d",rateselected) allready takes care of catching character input, and returns 0 if that is the case. So you should change the isalpha test to a rateselected == 0 test.
Also, scanf will never return EOF. It will return 0, and then you need to test feof(stdin) to see if you really hit the end of input. (which would correspond to a ctrl-Z for keyboard input).
Remove the isalpha(rateSelected).
isalpha() checks if the value passed as parameter is an alphanumeric character - but you are passing the int value which you have just read.
However, this is still not sufficient - you would need to catch the return value from scanf() to check if scanf() has actually read an int. But if no int was entered, the characters are not discarded so that the next scanf() will again try to convert them, which leads to an endless loop.
Better use the solution provided by #dasblinkenlight.
Use this:
int e;
while ((e = scanf("%d", &rateSelected)) != EOF)
{
scanf("%*[^\n]"); // this clean your input buffer
if (e==0 || rateSelected>5 || rateSelected<1) {
printf("please enter a number between 1-5:\n");
continue;
}
instead of
while ((scanf("%d", &rateSelected)) != EOF && rateSelected != 5)
{
if (rateSelected > 5 || isalpha(rateSelected) ==1){
printf("please enter a number between 1-5:\n");
continue;
}

Resources