Single line comparison to several values in C - c

For example maybe we have an if statement that wants to check if a variable is equal to 4 different values, perhaps something like
if(x == 1,2,3,4){ do something }
what is the proper syntax to do this in C? I know the comma works in some other language, I can not seem to figure how not to have several different if checks. The only other thing I could come up with is having to do
if((x == 1)||(x ==2)
but I will no doubt have more than 4 and that will get annoying fast. I didn't see any other question like this, if you know of it, point me towards it.

I would do it with a switch if the values are constant:
switch(x)
{
case 1:
case 2:
case 3:
case 4:
//do something
break;
}
if the numbers are continuous you can use if (x >= 1 && x <= 4)

First of all, shorthands, as mentioned by mch in the other answer,
if ( (x >= 1 && x <= 4) || (x >= 10 && x <= 40) || ....) //whatever condition
Otherwise, (not a single line comparison) in case you are OK with using gcc extensions, there's a feature called case-range.
There, you can specify a range of values. Something like
case 1 ... 5:
will be valid.
Finally, a fall-through switch case also may come handy, like
switch(val)
{
case 1:
case 2:
case 3:
case 4:
case 5:
break;
case 6:
case 7:
break;
default:
break;
}

Related

Will adding a sequence of consecutive numbers after a sequence of ordered, but non-consecutive numbers, affect the optimization of a switch statement?

I have a switch which has some random numbers: 1,5,16...
Imagine there are 10 or 20 of them.
After them, I have some macros where I can assign my own signed int numbers. So they can be 1000, or 32000...
Imagine there are also 10 or 20 of those.
Now, my question is:
will ordering and making my numbers consecutive even help with optimization if the former numbers are ordered but not consecutive?
will using smaller numbers (like 1000, compared to 32000) affect performance in any theoretical way?
Code:
switch (x) {
case 1:
// stuff
break;
case 5:
// stuff
break;
case 16:
// stuff
break;
case 32000:
// stuff
break;
case 32001:
// stuff
break;
case 32002:
// stuff
break;
defult:
break;
}
If you need hardware specifics, imagine we are talking about the most default theoretical scenario: gcc, intel, no optimizations.
Please advise.
That depends on your compiler, usually it should not help. Some compiler may implement a binary search, others may implement a if/else chain. But as long as not all of your numbers are consecutive there won't be a jump table*. The order of your case statements does not make a difference.
switch (x) {
case 1:
...
break;
case 3:
...
break;
case 5:
...
break;
}
and
switch (x) {
case 1:
...
break;
case 5:
...
break;
case 3:
...
break;
}
Will be (usually) compiled to exactly the same code.
EDIT:
If larger numbers than the type of x can handle, the result is undefined. Otherwise it does not make a difference.
*Sometimes it can be worth, for example if there are just gaps between the numbers.

Why my code which uses a logical expression as a case label throws error?

switch(at){
case (at>0 && at<5) :
printf("Average Time Taken (Hrs)\n%d.0",at);
printf("Your Salary is Rs.%d",pj*1500 + 5000);
break;
rest of the codes are similar. And i'm getting error for this case (at>0 && at<5) :
I'm afraid this is not possible. Quoting C11, chapter §6.8.4.2
The expression of each case label shall be an integer constant expression and no two of
the case constant expressions in the same switch statement shall have the same value
after conversion. [....]
so the case label expression cannot be a runtime-generated value dependent.
You can, use a fall-through syntax to achieve what you want, something like
switch(at){
case 1:
case 2:
case 3:
case 4:
printf("Average Time Taken (Hrs)\n%d.0",at);
printf("Your Salary is Rs.%d",pj*1500 + 5000);
break;
//some other case
Otherwise, if you're ok with using gcc extension, you can use case-range syntax, something like
switch(at){
case 1 ... 4:
printf("Average Time Taken (Hrs)\n%d.0",at);
printf("Your Salary is Rs.%d",pj*1500 + 5000);
break;
The case value in a switch statement must be a compile time constant (such as a literal, or a static const, or a #define to one of those). For what you are trying to do, you need an else if chain:
if (0 < at && at < 5) {
printf("Average Time Taken (Hrs)\n%d.0",at);
printf("Your Salary is Rs.%d",pj*1500 + 5000);
} else if (5 <= at && at < 10) {
// Your code here
Note that I have reversed the arguments to the first comparison (and the direction). If you have multiple comparisons of the same variable, I find it much easier to read if they are all in the same direction.

Why are these cases without statements ahead?

Into the following code case 1: to case 2: and case 5: seem to have no code for execution. My question is can't we just omit typing them?
switch(c)
{
case 1:
case 2:
case 3:
a++;
break;
case 5:
default:
b++;
break;
}
They fall through, i.e. if you encounter 1 or 2 it will jump into these cases and since there's no break just continue with case 3. So you can not omit those, because otherwise 1 and 2 would jump to default.
Similarily, case 5 will fall through to default, meaning that you could omit case 5.
Essentially, switch statements can be imagined as goto-jumps to the appropriate positions. That means, that the program will jump into the appropriate case and continue working from there until it finds break or return. This means, that you have to write break or return explicitly if you don't want your program to continue execution in the subsequent case.
No, you can't omit them. Basically cases 1 and 2 will fallthrough to 3. Omitting them would cause the default case to be executed for input values 1 and 2.
It's a fallthrough case. That means the cases fall down until a break appears. So a++ would be excecuted with c being 1, 2, 3.
The cases for 1,2 and 3 mean that if c=1,2 or 3 then a++. If c=5 or different then b++ - note that the code only stops if you hit a break so that c=1 gives the same as c=3 for example.
They may be omitted but the result would be different.
Basically what the code does is for c equal to 1, 2, or 3 a++ gets executed, otherwise, b++ does.
In this case case 5: should be omitted after all as it will falls in the default: case.
My question is can't we just omit typing them?
TL;DR -- In your case, No. They have some meaning.
Quoting C11, chapter §6.8.4.2, The switch statement
The integer promotions are performed on the controlling expression. The constant expression in each case label is converted to the promoted type of the controlling expression. If a converted value matches that of the promoted controlling expression, control jumps to the statement following the matched case label....
That means, based on the value of c here, the particular "case" will be executed.
Fine. Wait, now we know where to take the control to start execution, but where to stop, exactly?
You're thinking "before the next case body?"
Well, not exactly. It does not automatically stop . Usually, we use a break; statement after each case block, to "mark" the end of that particular case. In case, the break; is not present, it will continue to execute the statements from following cases (if any), as if they are part of the same case block and it will continue until it reaches the end of switch body.
Now, to elaborate, in your case, if the value of c is either 1, 2 or 3, it will execute the statement block for case 3. Notice, there is no break; statement after case 1: and case 2: labels. It is kind of "fall-through" technique.
OTOH, if you remove the case 1: and case 2: labels, if c holds 1 or 2, the control won't reach the block after case 3:, it will go to default: label.
However, case 5: will fall through to default: label, making it redundant. This once can be removed.
You can indeed omit a case. This switch statement
switch(c)
{
case 1:
case 2:
case 3:
a++;
break;
case 5:
default:
b++;
break;
}
can be rewritten like
switch(c)
{
case 1:
case 2:
case 3:
a++;
break;
default:
b++;
break;
}
without using label case 5: . But you may not exclude labels case 1: and case 2:
With these labels the switch statement can be rewritten using the if-else statement the following way
if ( 1 <= c && c <= 3 )
{
a++;
}
else
{
b++;
}
On the other hand without these case labels the corresponding if-else statement will look like
if ( c == 3 )
{
a++;
}
else
{
b++;
}
As you can see yourself there is a big difference between these two if-else statements.

Switch statement not compiling

Hello I've been sitting here for quite some time trying to figure out why this isn't working but I haven't had luck succeeding!
#include <stdio.h>
main(void)
{
int mark;
printf("Please enter the mark\n");
scanf("%d", &mark);
switch(mark){
case (mark <40):
printf("That's a fail");
break;
case (mark >=40 && <60):
printf("That's a pass");
break;
case (mark >=60 && <70):
printf("That's a merit");
break;
case (mark >=70):
printf("That's a distinction");
break;
}
}
For comparisons where the exact value is not known, use if-else blocks. You are trying to use a switch statement like an if-else block, and it does not work properly. A proper switch would look like
switch(mark) {
case 40: //if mark is 40, no more, no less
...
case 60: //same
...
}
Because you don't want to write out 40 lines that all lead to the same statement, just use
if(mark < 40) { ... }
else if(mark < 60) { ... }
From K&R:
"The switch statement is a mult-way decision that tests whether an expression matches one of a number of constant integer values, and branches accordingly."
That is, you can't do what you're trying to do. Each case needs a constant statement, such a simple int or char value.
For what you want to do you'll need if/else. Also, see jaap's answer on correct syntax for your boolean statement.
It's working fine, the compiler is preventing you from compiling something that's not valid C.
The case labels must be actual integer constants, not expressions that do further calculations.
You should use if/else if to check your various conditions.

How to write "if x equals 5 or 4 or 78 or..." in C

I have a quick question about using logical operators in an if statement.
Currently I have an if statement that checks if x equals to 5 or 4 or 78:
if ((x == 5) || (x == 4) || (x == 78)) {
blah
}
And I was wondering if I could just condense all that to:
if (x == 5 || 4 || 78) {
blah
}
Sorry for such a basic question, I've just started learning C.
There is no shortcut, but you need to fix your equality operator.
if ((x == 5) || (x == 4) || (x == 78)) {
First, you're using assignments not equality tests in your ifs. The first method (with suitable substitutions for equality) is the best way to do the test, though if you have a lot of possible options, there might be better ways. The second way might compile, but it won't do what you want, it will always return true since both 4 and 78 evaluate to true and what you are doing is evaluating whether 5 (the result of assigning 5 to x) or 4 or 78 are true. A switch statement might be one possible alternative.
switch (x) {
case 4:
case 5:
case 78:
blah...
break;
default:
}
There's no shortcut for the if statement, but I suggest considering:
switch (x)
{
case 4:
case 5:
case 78:
/* do stuff */
break;
default:
/* not any of the above... do something different */
}
No you cannot and the test for equality is ==, not =
#uncle brad is spot on, but later you'll probably learn about something called a switch statement. It looks funky but is often used in these sorts of situations (where several possible values of a variable all have the same effect):
switch (x) {
case 4:
case 5:
case 78:
// ...
break;
}
Though you'd only want to use a switch statement when the meaning of an if statement is less clear--most compilers these days are smart enough to generate optimal machine code either way.
It's been answered in the time it took me to log in, but you could use the switch, and break it out into a function
int isValid(int toCheck) {
switch(toCheck) {
case 4:
case 5:
case 78:
return 1;
default:
return 0;
}
}
Then you would just call the method every time you needed to check the int against the established cases.
Admittedly, this example is rather silly, but for a bigger selection of cases, and ones that were evaluated repeatedly, you could do something like this to simplify and reuse some code.
No, sorry, you can't; you have to write all the expressions out. For very long lists of numbers to compare to, you could put the numbers in an array, and loop over the list; but you'd have to have a dozen numbers or so before that started to look like a good idea.
No, you cannot do this in C. Your first code sample is also incorrect. There is an important distinction between assignment (=) and equivalency (==) in C. When you wrote x = 5 in your expression, this will actually compile and evaluate to either 0 or 1 (false or true) before being logically OR'ed with the next part of the expression!
Your second code sample is also valid C, but it does not do what you want it to do. You read the statement as "(x is assigned to 5) or true or true". This is because any non-zero value in C is logically true. Thus, x will contain the value 5, and evaluate to true, making your if condition true. The rest of the expression does not matter since the || operator short-circuits.
One alternate thought: While there's no "shortcut", if you have a lot of numbers it may be easier for code length and typing sanity to put them all into an array and check against the array in a loop. If you have to compare against many numbers more than once, sort them in an array and use binary searching.
For 3 numbers, though, you have to do it the "long" way.
You can do the for loop if it's a long list, how ever that doesn't really handle the logical operators :-...
#include <stdio.h>
int forbiddenList[13] = {5, 4, 78, 34, 23, 56, 4, 7, 6, 4, 33, 2333, 0};
int length = 13;
int main() {
int mysteryNum;
printf("type a number: ");
scanf("%d",&mysteryNum);
int i;
for (i = 0; i <= length; i ++)
{
int target = forbiddenList[i];
if (mysteryNum == target)
{
printf("You have chosen of the forbidden list!\n");
printf("YOU SHALL NOT PASS!!\n");
}
}
return 0;
}
er... haven't done c... ever... you should take C++...
int preconditions[] = { 4,5,78 }; // it should be in most likely order
int i = 0;
for(;i<3;++i) {
if( x == preconditions[i] ) {
// code here.
}
}
The syntax is:
if(condition1 || condition2 || condition3 || ...){
// Do something
} else {
// Do something
}
Answer to your question:
if( (x == 5) || (x == 4) || (x == 78) ){
//do something
} else {
//do something
}

Resources