Why is the while loop not working? - c

im new to c language and i am facing some problems with my code.. I have to make a program that computes the prices for renting cars but the while loop is not functioning properly.The scanf above the while condition is %s and not %c because it wont let me give a characther when it is %c.Thank you in advance.
int main(){
float skms, ekms, tkms, price;
char catcode;
int days;
do{
printf("Selected rental program:\n");
scanf("%c",&catcode);
printf("Enter number of days:\n");
scanf("%d",&days);
printf("Starting kilometers display:\n");
scanf("%f",&skms);
printf("Kilometers display at end of rent:\n");
scanf("%f",&ekms);
tkms=(ekms/10)-(skms/10);
switch(catcode){
case'a':
case'A':
price=ammountDueA(days, tkms);
printf("%.2f\n",price);
break;
case'b':
case'B':
price=ammountDueB(days, tkms);
printf("%.2f\n",price);
break;
case'c':
case'C':
price=ammountDueC(days, tkms);
printf("%.2f\n",price);
}
printf("Select rental program.('Q' or 'q' to exit)\n");
scanf("%s",&catcode);
}while(catcode==!'Q'&&catcode==!'q');
printf("%c",catcode);
return 0;
}

By "not working", I suppose you mean that it never enters a second iteration, but that is exactly what it is supposed to do. catcode==!'Q'&&catcode==!'q' is true if catcode is equal to !'Q' and equal to !'q'. 'Q' is some non-zero integer (depends on your system, but is probably 81), and !'Q' is zero. Similarly, !'q' is zero. catcode isn't zero, so the loop terminates.

There are two problems in your code:
First of all, the specifiers in scanf...
scanf("%s", &catcode);
This won't work. The "%s" specifier expects its corresponding argument to be a char* to a buffer of unspecified length (i.e: this has the same problem as gets()). You probably meant "%c", whose corresponding argument shall point to a single character. Now, your format specifier is not recommended to be "%c", but " %c", because that extra space indicatesscanf()to ignore all whitespace it can before"%c"`. So, that line becomes...
scanf(" %c", &catcode);
Now, you're right, there's a problem in your while loop:
while(catcode==!'Q'&&catcode==!'q');
Let's "expand" this with whitespace, to make what you (apparently) intended more obvious (that's reason #1 to use spaces between operators!)...
while(catcode ==! 'Q' && catcode ==! 'q');
For you it appears okay. Not for me. The C language does not define any operator ==!, rather, it defines operator == (that compares for equality), and operator ! (that negates its single operand). The compiler would have understood that line as...
while(catcode == !'Q' && catcode == !'q');
Now, what does that mean? If the operand is non-zero, the ! operator returns zero (in this case, the null character, '\0'). Otherwise, it returns a non-negative value (usually 1 (does the standard mandates this?)). Because 'Q' is not '\0', and same for 'q', that means that your loop is effectively...
while(catcode == '\0' && catcode == '\0'); // Think of '\0' as 0
Absolute non-sense expressed in code! The solution is to simply use operator != (compares for inequality)...
while(catcode != 'Q' && catcode != 'q');
I hope this has led some light on you!

Related

If statement executing regardless of the condition [duplicate]

This question already has answers here:
Program not recognizing character inputs in if-else statements
(5 answers)
Closed 1 year ago.
I'm writing a C program that asks the user for a variety of inputs, one is a Yes or No question. If you put Y, or y, the If statement is supposed to execute. However, no matter what you input, it goes through with the If statement.
double phonePrice;
double phoneTax;
double phoneTotal;
double phoneApplePrice;
double phoneSubtotal;
double temp;
int yearsAppleCare;
char userAnswer;
//prompting for price
printf("Enter the price of the phone> ");
scanf("%f", &phonePrice);
fflush(stdin);
//prompting for iphone
printf("Is the phone an iPhone (Y/N) ?> ");
scanf("%c", &userAnswer);
fflush(stdin);
//nested if statements asking for apple care amount
if(userAnswer=="Y"||"y")
{
printf("Enter the number of years of AppleCare> ");
scanf("%d", &yearsAppleCare);
if(yearsAppleCare<=0)
{
printf("You must choose at least 1 year of AppleCare");
return 0;
}
}
Any help with this would be appreciated.
For starters this call
fflush(stdin);
has undefined behavior. Remove it.
Instead of this call
scanf("%c", &userAnswer);
use
scanf(" %c", &userAnswer);
^^^^
to skip white spaces in the input buffer as for example the new line character '\n'.
Also for double variables use the conversion specifier %lf. For example
scanf("%lf", &phonePrice);
The condition in the if statement
if(userAnswer=="Y"||"y")
is equivalent to
if( ( userAnswer=="Y" ) || ( "y" ) )
As the string literal "y" that is implicitly converted to a pointer to its first element is not equal to a null pointer then the condition always evaluates to logical true.
You need to write
if( userAnswer == 'Y' || userAnswer == 'y' )
using integer character constants 'Y' and 'y' instead of the string literals.
Error is here:
//nested if statements asking for apple care amount
if(userAnswer=="Y"||"y")
{
Should be:
//nested if statements asking for apple care amount
if(userAnswer == "Y" || userAnswer == "y")
{
Wait! No!
Should be:
//nested if statements asking for apple care amount
if( strcmp(userAnswer, "Y") == 0 || strcmp(userAnswer, "y") == 0)
{
Why?
What does == mean?
In C language, == means the two objects are equal. In the case of strings, the objects are char*, I.e. pointers to char. These will be equal if and only if the memory address is the same. This will not be true in this case.
Why? Because one string is compiled into the program and initialised as the program starts, and the other is provided by the user into temporary memory. These will be at different addresses so the pointers will not be the same.
What you probably want is to compare the contents of the memory locations pointed to by the two pointers.
For that purpose the strcmp function is provided. This function returns zero if the strings are the same. You may also want to consider stricmp.

C: scanf doesn't work as I want

I want that the program controls the user's input (must be a char/letter), but if I put "xx" it goes out of the loop, why?
char c;
int i = 0;
do{
if(i!=0){
printf("Wrong!\n");
}
printf("Insert char: ");
scanf(" %c", &c);
i++;
}while(c<'a' && c>'z' && c<'A' && c>'Z');
-----> Edit/correct
This piece of code should read a single character from the keyboard (must be a letter, it does not matter whether it is lowercase or uppercase), if it were not so I write "wrong".
As you told me I corrected the condition of the do/while, now the code is:
do{
if(i!=0){
printf("Wrong!\n");
}
printf("Insert char: ");
scanf(" %c", &c);
i++;
}while(!((c>='a' && c<='z') || (c>='A' && c<='Z')));
Input examples:
What I expect
'a' -> exit to the loop
'aa' -> remain in the loop
'.' -> remain in the loop
'..' -> remain in the loop
What happens
'a' -> exit to the loop
'aa' -> exit to the loop
'.' -> remain in the loop
'..' -> remain in the loop (but it print me two time "wrong")
If I do not put the space in the scanf, so ("%c"), the program prints me automatically "wrong" and "insert char" (it just makes a loop)
(p.s. I apologize if I had not explained very well the problem before)
Your condition for
while(c<'a' && c>'z' && c<'A' && c>'Z');
will never be true.
but if I put "xx" it goes out of the loop, why?
Since do-while is an exit-condition loop, the only time you enter the loop is the first time.
The specifier %c indicates a character. Accordingly, your while loop checks for single characters but you give as an input a string.
If you want to input a string, change your scanf statement to :
scanf("%s", &s);
as the specifier %c indicates a string. You will need to modify your while loop accordingly in order for your condition to become true at some point.
while(c<'a' && c>'z' && c<'A' && c>'Z')
is always false, that's why.
If it were true:
if(i!=0){ printf("Wrong!\n");}
will always print false(except the first time).
I don't know exactly what you want.
Your problem is in the condition, it's always false.
Example code:
#include <cstdio>
#include <cctype>
int main ()
{
char c;
do scanf("%c", &c);
while(tolower(c)<'a' || tolower(c)>'z');
printf("%c\n",c);
return 0;
}

Scanning the characters properly except '+' and '-'

I am trying to scan an arithmetic expression like : 4+3-2*6*(3+4/2)#
What I tried is following code. It's running fine and scanning each character properly except '+' and '-'.
Why it is not scanning only two particular characters!
void scan(){
int n,tmp,digit_no;
char c;
scanf("%c",&c);
while(c!='#'){
if(isdigit(c))
{
tmp=c;
scanf(" %d",&n);
digit_no=numPlaces(n);
n=(tmp-48)*ipow(10,digit_no)+n;
push_n(n);
n=0;
}
else if(c=='+' || c=='-' || c=='*' || c=='/' || c=='(' || c==')' || c=='=' || c=='^')
push_o(c);
scanf("%c",&c);
}
}
Do not get a char, test for a digit, scan an int and then try to put them together. This fails the code's intent with input like for input like "3-2", "1 23", "1+23" as well explained by #John Bollinger as scanf("%d",&n) is consuming the + -.
Instead put the digit back into stdin and then scan for the int.
if(isdigit(c)) {
ungetc(c, stdin);
scanf("%d",&n); // cannot fail as first character is a digit - may overflow though
push_n(n);
n=0;
}
Also suggest to detect EOF and use is...() functions correctly.
// char c;
// scanf("%c",&c);
int c;
// while(c!='#'){
while((c = fgetc(stdin)) !='#' && c != EOF) {
...
// scanf("%c",&c);
}
Detail: is...() expects an int in the range of unsigned char and EOF. Calling them with a char is a problem when the value is negative.
You are mistaken: scanf() is scanning the '+' and '-'. It is simply scanning them as part of the decimal number that follows.
With your example input, the program first scans a '4', which is a digit. It then proceeds to execute scanf(" %d",&n);, which scans the next two characters, "+3", as the number 3, because fields described by %d may optionally have a leading sign character, either '-' or '+'. The scanning stops at the first '-', since a decimal number cannot contain an internal or trailing '-', and indeed, the '-' is scanned as the next character. You would see different results for '-' or '+' following a two-digit number or a parenthesis.
Overall, your approach to scanning numbers is fundamentally flawed. Not only does it run aground on the optional sign character, but I see no way it can do the right thing when the second-most-significant digit of the number you are trying to read is a '0'. That is, your approach cannot distinguish "401" from "41". You cannot successfully scan the tail of a number as a number in its own right without losing information you need.

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

isdigit() in a function

I have a function which takes an integer input by the user.
So I have:
scanf("%d, &x);
And then, the function:
test(int x);
Inside test(), I wanna check if the input is a digit or a character, so I tried:
if (isdigit(x))
// piece of code
printf("Done!\n");
else
printf("Bye!\n");
However, isdigit() does not seem to be working as the program is outputting "Bye!" immediately. What could be the problem?
Thanks.
You are passing integer not char!
isdigit(x) check whether x is a digit char e.g. '0', '1' but not 0, 1 what you are passing.
It behaves like:
isdigit('h') returns 0
isdigit('1') returns 1
isdigit(1) returns 0 // your are passing this
Read manual:
Standard C Library Functions ctype(3C)
isdigit() Tests for any decimal-digit character.
isdigit tests a character:
isdigit('5') == true;
isdigit(5) == false;
remove the semicolon:
if (isdigit(x)); // <===
Because of the semicolon, if it is a digit you execute an empty statement.
The C library function void isdigit(int c ) checks if the passed character is a decimal digit character.
The isdigit() function returns non-zero if c is a decimal digit otherwise 0.The input argument is an int, the value of which the application shall ensure is a character representable as an unsigned char or equal to the value of the macro EOF. i.e
ensure that your value is enclosed in single quotes.
You also seemed to have a ; after the if statement which shifts the expected control flow.
char x;
scanf(" %c", &x);
if (isdigit(x))
printf("Done!\n");
else
printf("Bye!\n");
Suspect OP wants to read a char
char x; // new type
scanf(" %c", &x); // new format specifier
if (isdigit(x)) // remove ;
// piece of code
printf("Done!\n");
else if (isalpha(x)) // added test #Joachim Pileborg
printf("Is a alpha!\n");
else
printf("Bye!\n");

Resources