Do-while loop not observing truth assignment (C) [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 7 years ago.
Improve this question
My C project is a Windows console app that takes the time signature and BPM from a user's musical project and returns the length of a bar in seconds.
I am trying to use a do-while loop to add a "continue/exit?" prompt at the end of each successful calculation
Here is the source code for that function. It performs one calculation based on user input, then terminates.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char timeSignature[6];
float BPM;
float beatsPerBar;
float barLength;
printf("Enter the working time signature of your project:");
scanf("%s",timeSignature);
beatsPerBar = timeSignature[0]-'0';
printf("Enter the beats per minute:");
scanf("%f", &BPM);
barLength = BPM / beatsPerBar;
printf("%f\n", barLength);
return 0;
}
After each successful calculation, I want to prompt the user to choose "y" to return to the initial input prompt or "n" to end the program and exit the command prompt.
This later update includes a do-while loop that is intended to add the feature.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <unistd.h>
int main()
{
do{
char timeSignature[6];
char anotherCalculation;
float BPM;
float beatsPerBar;
float barLength;
printf("Enter the working time signature of your project:");
scanf("%s",timeSignature);
beatsPerBar = timeSignature[0]-'0';
/*
* Subtracts the integer value of the '0' character (48) from the integer value
* of the character represented by the char variable timeSignature[0] to return
* an integer value equal to the number character itself.
*/
printf("Enter the beats per minute:");
scanf("%f", &BPM);
barLength = BPM / beatsPerBar;
printf("%f\n", barLength);
Sleep(3);
printf("Would you like to do another calculation? (Y/N)");
scanf(" %c", &anotherCalculation);
}while((anotherCalculation = 'Y'||'y'));
if((anotherCalculation != 'Y'||'y'))
{
printf("Goodbye!");
return 0;
}
return 0;
}
When I compile, there are no errors, but when I run it, the program loops after ANY input. Why is the code ignoring my truth assignment? What can I do to fix this?

Change this:
while (anotherCalculation = 'Y'||'y')
To this:
while(anotherCalculation == 'Y'|| anotherCalculation == 'y')
Otherwise you're doing:
while (anotherCalculation = ('Y'||'y'))
Note I also changed the assignment = to comparison ==.
Same goes for your if later:
if (anotherCalculation != 'Y'||'y')
Should be:
if (anotherCalculation != 'Y'|| anotherCalculation != 'y')
The if is redundant by the way, you've already left the while loop, so the user does not want any more calculations.

Convert your value to an upper-case letter before doing the comparison:
while(toupper(anotherCalculation) == 'Y');
That will accept either a lower-case or upper-case 'Y', and keep your code simple and straightforward.

Your problem is with the following line of code:
while((anotherCalculation = 'Y'||'y'));
Your first problem is that you are assigning to the variable anotherCalculation and then testing that value. This is because in C the = (assignment) operators can be used in test statements and the value that was set will be returned into the statement basically making your test statement the following:
while('Y'||'y');
Also there is a fault in the logic within your test statement even after substituting the = for ==,
What you are actually doing there is the same as:
TRUE if anotherCalculation == 'Y' or if 'y'.
Since 'y' actually has a value and FALSE is 0 in standard C, your loop will continuously run because it will always have a TRUE value.
To fix all errors, what that line actually needs to be is:
while(anotherCalculation == 'Y'|| anotherCalculation == 'y');
Finally, if you want to make this code more readable and avoid double testing, you can convert the input to uppercase and test that:
while(toupper(anotherCalculation) == 'Y');

First, you're using a mathematical notation for your logical checks that makes no sense in C, and you're using the assignment = operator instead of the "test for equivalence" == operator.
}while((anotherCalculation = 'Y'||'y'));
Should be:
}while((anotherCalculation == 'Y'|| anotherCalculation == 'y'));
Second, save yourself some hassle down the road, and use fgets() to get a line of a text, and parse it.
Finally, read into things like "trailing newlines" with scanf() and fgets(). The scanf() function, for example, won't "eat up" the newline at the end of your input, and you'll get unexpected behavior. This very question appears on SO once per month at least.

Logical operators don't work like that. x == a || b doesn't evaluate as "x is equal to one of a or b"; instead, it evalutes as "x is equal to the result of the Boolean expression (a OR b)". If you want to compare x against different values, you must write it as
x == a || x == b
But you have another problem, you've used the assignment operator = where you meant to use the comparison operator ==1:
while((anotherCalculation = 'Y'||'y'))
^
|
ooops
You're performing a logical-OR of two non-zero values, which evaluates to 1 (true), and assigning the result to anotherCalculation. The result of the expression is the value of anotherCalculation after the assignment (1), so you've effectively written
while( true )
You need to use the == operator for equality comparison, and you must do an explicit comparison on each side of the || operator:
while ( anotherCalculation == 'Y' || anotherCalculation == 'y' )
You can clean this up a bit by converting your input to a specific case before doing a comparison, getting rid of the need for the || operator altogether:
while ( tolower( anotherCalculation ) == 'y' )
or
while ( toupper( anotherCalculation) == 'Y' )
1. A bright young coder named Lee
wished to loop while i was 3
When writing the =
He forgot its sequel
And thus looped infinitely

This is not doing what you expect:
}while((anotherCalculation = 'Y'||'y'));
Nor is this:
if((anotherCalculation != 'Y'||'y'))
You should be doing this:
}while((anotherCalculation == 'Y') || (anotherCalculation =='y'));
And this:
if((anotherCalculation != 'Y') && (anotherCalculation !='y'))

TLDR; Change your condition to
while( anotherCalculation == 'Y' || anotherCalculation == 'y' );

Related

Problem: keep prompting user to enter code until the right they input the right values

I'm having an error with the following code. It's relatively simple but I can't figure out where I'm going wrong. Here's a part of the code:
int target=0,nextRow;
char nextCol;
while(target == 0)
{
printf("Enter a valid target: ");
scanf("%c%d",&nextCol,&nextRow);
if(nextCol>= 'a' && nextCol <= 'z') /* convert to uppercase */
nextCol=nextCol-32;
if(nextRow>row || nextRow<1 || nextCol<'A' || (nextCol-64)>col)
target=0;
else
target=1;
}
Essentially the user is prompted to input a char and int e.g. B4, C8 etc. Col and Row are predefined integers. If the user-input values are out of bounds target remains as 0. Else target=1 so the loop will exit. When I run this and keep inputing invalid values, "Enter a valid target" starts repeating. Why?
Image of the error
Apparently, the condition (nextCol-64)>col seems to be misplaced.
If you input f.e. 'b' as input for nextCol, the expression would be evaluated to 2 > col which seems to be wrong.
Also I consider that col and maybe even row have the value of 0 in which case, the corresponding conditions would always evaluate to true and the loop will never terminate as it seems to do.
Overthink the logic of your program!

C Integer range must meet 3 different conditions

If I wanted to limit the range of values to be assigned to an integer to three different conditions. eg; Must be between 9 and 95 and also be divisible by 5 would this be the correct way to accomplish this?
I've been told that i can have multiple conditions as long as they are separated by && but I am having little success with my code.
if (input >= 5 && input <= 95 && input %5)
Your code seems fine to me, except for this line.
if (input >= 5 && input <= 95 && input %5)
The expression input % 5 returns the remainder of input/5. You want input to be divisible by 5, which happens when input % 5 returns a remainder of 0. Since C interprets 0 as false, and pretty much all other integers as true, this expression will do exactly the opposite of what you want it to do. Try using
if (input >= 5 && input <= 95 && (input % 5 == 0))
That should do what you want it to do.
There are a number of issues with your code as it stands. First, the outright bugs:
The expression input % 5 will give you the remainder when divided by five. This means you will get zero if it is a multiple, non-zero otherwise. Unfortunately, zero is treated as false so this will only be true if input is not a multiple. The correct expression is (input % 5) == 0.
If you enter something that cannot be interpreted as an integer, the scanf will fail and input will be left at whatever value it was beforehand. This should be caught and acted upon, by checking the return value - this gives you the number of items successfully scanned so should be one.
Your code seems to return the value if okay but return nothing if it's invalid.
Next, while not bugs, these things are my personal preferences which can make code easier to read and maintain:
I prefer to explicitly separate sub-expressions so I never have to worry about precedence rules (provided it doesn't make the expression unreadable in the process). To that end, I would make the full if statement if ((input >= 5) && (input <= 95) && ((input % 5 == 0)).
I'm not a big fan of the if (condition) transferControl else ... construct since the else is totally superfluous.
I also prefer error catching to be done in a localised fashion at the start, catching problems early. Only after all checks are passed do you do the success portion.
A function (assuming it is a function, which seems likely) should generally do one thing, such as check if the value is valid. Writing issues to standard output is probably best left to the caller so that the function is truly re-usable. It would be better to have a function do the check and return some value to indicate whether or not there was a failure, along with the value if valid.
It's usually better to use puts("something") rather than printf("something\n"). The printf call is best left to where you actually need to do argument formatting.
Taking that all into account, the code that I would posit would be along the lines of:
#include <stdbool.h>
bool InputValidRangeAndMultiple(
unsigned *pValue,
unsigned minVal,
unsigned maxVal,
unsigned multVal
) {
unsigned input;
// If no unsigned int available, error.
if (scanf("%u", pValue) != 1) return false;
// If value invalid in any way (range or multiple), error.
if ((*pValue < minVal) || (*pValue > maxVal)) return false;
if ((*pValue % multVal) != 0) return false;
// Value is now deemed okay.
return true;
}
Calling that function can be done thus, with the prompts and errors handled outside the "input and check" function:
#include <stdio.h>
unsigned value;
puts("Enter Value.\nValue must be divisible by 5 and within 5 and 95...");
if (! InputValidRangeAndMultiple(&value, 5u, 95u, 5u)) {
puts("Invalid input...");
returnOrDoSomethingIntelligent();
}
// The 'value' variable is now valid.

how to use multiple input values to call same function?

First I have to say that i'm completely new to programming and this is my first program. I've watched a 5 hour tutorial before I started this and now I've run into my first problem I can't solve myself. So I hope someone here can help me!
I've written the following code
void printMainMenu();
void printTourMenu();
void assignment1();
void assignment2();
void assignment3();
void assignment4();
void assignment5();
void assignment6();
int main()
{
int userInput;
printMainMenu();
printf("\n\n");
scanf("%d", &userInput);
if(userInput == 4||6)
{
printTourMenu();
}
if (userInput == 1)
{
assignment1();
}
if(userInput == 2)
{
assignment2();
}
if(userInput ==3)
{
assignment3();
}
if(userInput ==5)
{
assignment5();
}
return 0;
all the functions are just pure printf so I just want the user to be able to print 6 different things depending on what they click on, but instead of making two if-statements to do the very same thing depending on the input, I just try and make an if-statement that works with multiple inputs.
the problem is in the if(userInput == 4||6) which i've tried with both
4, 6 and 4||6 where it keeps printing the printTourMenu no matter what I input and then the function i'm actually calling. With 4&&6 it prints printTourMenu only when I input 4 but not when I input 6
so what am I doing wrong? I hope someone will help this beginning programmer :D
Actually, the answer was simple and provided ASAP by Steve Summit:
if (userInput == 4||6)
doesn't do the expected. The correct would be:
if (userInput == 4 || userInput == 6)
IMHO, you should now ask:
So, if if (userInput == 4||6) is wrong – why didn't the compiler complain? (I assume it didn't although I didn't try.)
There are two reasons for this and IMHO you should know these reasons (as you did not yet learn them from your C book).
There are no special boolean types in C. Instead, every integer ≠ 0 is counted as TRUE but 0 is counted as FALSE. Hence, logic operators compute integers, comparison operators as well.
Thus, userInput == 4 || 6 is just a valid arithmetic expression and it has a precise result.
To understand how userInput == 4 || 6 is evaluated you need to know about C operator associativity and precedence also. Both terms can be found by google very easy (because they probably are searched quite often (at least periodically by me)).
I recommend the reference table of cppreference.com: C Operator Precedence.
Studying this table, we see:
operators == and || are both evaluated from left to right.
operator == has lower precedence as operator ||, i.e. == binds stronger, i.e. == is computed first.
Hence, it's starting with two cases:
userInput contains value 4: ⇒ userInput == 4: 1
userInput contains anything else: ⇒ userInput == 4: 0
These first results are applied to the second operator || 6:
1 || 6: 1 (Remember, logic-or operator just checks whether at least one argument is not 0.)
0 || 6: 1
It shows that anything || 6 results in 1.
That's why it was printing the tour menu regardless what you input.
Don't forget: as well as in school math, it is allowed to use parentheses () to override associativity and precedence. So, if you are in doubt just put parentheses around. Normally, they don't have any impact on run-time performance (at least, not as long as you don't change the order of operator evaluation due to this).

Passing an array through "isalpha" through a loop

I've been at this for quite some time now and the existing answers offer little to no help. I am new to programming and am trying to write a sub-part of my program which tries to check whether any given input is constituted solely of alphabets.
For this, the idea I have in mind is to pass an entire array through the isalpha function by using a loop which passes each character at a time. The idea makes logical sense but I am having syntactic trouble implementing it. I will greatly appreciate any help!
Below is my code-
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(**<what I'm putting here is creating the problem, I think>**) = true)
{
printf("%c", p[i]);
}
}
You should modify your code as this (assuming you have the string type defined yourself):
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(p[i]) == true) // HERE IS THE ERROR, YOU HAD =, NOT ==
{
printf("%c", p[i]);
}
}
Operator = is for assignment and operator == is for comparison!
So what was happening? The assignment resulted in true, no matter what p[i] was.
As Quentin mentioned:
if(isalpha(p[i]) == true)
could be more elegant and error prune if written like this:
if(isalpha(p[i]))
Here is an example in C:
/* isalpha example */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int i = 0;
char str[] = "C++";
while (str[i]) // strings in C are ended with a null terminator. When we meet
// the null terminator, while's condition will get false.
{
if (isalpha(str[i])) // check every character of str
printf ("character %c is alphabetic\n",str[i]);
else
printf ("character %c is not alphabetic\n",str[i]);
i++;
}
return 0;
}
Source
Ref of isalpha().
C does not have a string type.
Tip: Next time post your code as it is!
Aslo, as Alter noticed, it would be nice to use:
isalpha((unsigned char)str[i])
and in your code
isalpha((unsigned char)p[i])
for safety reasons.
Your example is here.
I.e. parameter of isalpha() is i-th character of string p. The only question is how to access to i-th character. Usually you can use []. I.e. just use following code: isalpha(p[i]) (I see that you already use [] in call of printf).
Also isalpha(p[i]) = true is wrong condition. It looks like you planned to check isalpha(p[i]) == true (you can skip == true).
Late but:
both other answers say omitting == true is desirable, but don't say it is necessary for portability.
The C core-language operators == != < <= > >= && || which return a 'logical' value use an int value of 1 for true and 0 for false. In C99 and up with stdbool.h and by common convention before that true is 1 and false is 0, so e.g. if( (a < b) == true ) will work correctly, although it is redundant and many (including me) consider it poor style. Language elements that test a logical value, namely if(c) while(c) for(;c;) and the operands to && || and the left operand to ?: consider any value that compares equal to 0 to be false, and any other value to be true.
The character-classification routines in ctype.h as well as some other standard-library routines like feof(f) and ferror(f) are specified to return some nonzero int for true and 0 (an int) for false, and on many implementations the nonzero value used for true is not (always) 1. In those cases isalpha(whatever) == true might result in testing say 4 == 1 and fail even when whatever is an alphabetic character. OTOH isalpha(...) != false or isalpha(...) != 0 does work correctly if you really want to write something explicit.

(Extreme Noob here) Why wont this C code work?

Why won't this work, I'm very new to programming but I can't seem to figure out why this wont work correctly.
#include <stdio.h>
#include <math.h>
int main(){
int num1;
printf("Enter 1, 2, 3.");
scanf("%d", &num1);
if(num1 = 1)
printf("You entered one");
else if(num1 = 2)
printf("You entered two");
else if(num1 = 3)
printf("You entered three");
else
printf("Invalid");
}
In C it is valid to use assignment (int x = 5) within a conditional (if statement).
For example:
int x = 0;
if (x = 5)
{
}
This will evaluate to true (it returns 5 to the "if" and all non zero terms are true by convention) if the assignment could be done and the value != 0. Which, in this case, it can be done and returns 5.
You were likely looking for this:
int x = 0;
if (x == 5)
{
}
This will evaluate to false (0).
Remember: You use a single equal sign "=" to mean "assignment". Use a double equal sign "==" to mean "comparison".
Replace all the = with == and you should be fine (because = is used for assignment, while == is used to test for equality, which seems to be what you want to do)
In C, as in other many programming languages, the = operator means "assignment". When you do a = 3, that means "assign a with 3", which of course it's something that succeeds and returns true, that's why your program will always enter the first branch.
What you have to do is use the "equality testing" operator, ==, so that a == 3 returns true if and only if the value held by variable a is 3.
Your code having one mistake you have taken = instead of ==, in C = operator means assignment operator while== operator is used for comparision.
To clear about your doubts regarding operators read this link
http://www.tutorialspoint.com/cprogramming/c_operators.htm
And because you started with int main() just for compiler reasons put return 0; at the end of your program to be more correct.
It doesn't work because you need to change the = sign to ==. You use the equal sign sometimes when you declare a int or char. == is meaning equal to and you want to use that when your not declaring ints and chars.While != means not equal.You should also put a return 0; at the end of your program.

Resources