Comparison of several integer values for equality - c

If I have two integer values I can test for equality simply:
if (a == b)
if I have three integer values then I could do something like:
if ((a == b) && (a == c) && (b == c))
I've got a situation where I've got 6 values to test for equality, this approach is going to get verbose
Is their a better, and more C idiomatic (c-onic?) means to achieve this?
actually, just having written this I can see that:
if ((a == b) && (b == c) && (c == d)... )
is logically ok, i.e. you don't need all the combinations as a == b and b == c implies a == c
But in terms of clarity of expression how close can I get to:
if (a == b == c) ?

You're not going to get very close to a == b == c.
To cause experienced C programmers the least surprise, I think this is best is
if(a == b && b == c && c == d && d == e && e == f)
i.e. basically like what you have already, with less parentheses. I'm not always opposed to adding parentheses that make no difference to the compiler to help humans who don't know all the precedence rules, but I think comparisons separated by && (with no || mixed in) are a simple enough case that the parentheses are more clutter than they're worth.
If the variable names are long, putting it all on one line isn't going to be pretty, so maybe
if(a == b &&
b == c &&
c == d &&
d == e &&
e == f)
or this might be better since the duplication of the the a in every line will be immediately noticeable:
if(a == b &&
a == c &&
a == d &&
a == e &&
a == f)
If you really want it to be compact, the p99 preprocessor library offers this:
#include "p99_for.h"
if(P99_ARE_EQ(a,b,c,d,e,f))
which looks like John Zwinck's answer but doesn't require a helper function.

I can show you how to do it in a variadic macro, so we can write this:
if(EQI(a, b, c, d, e, f))
Here's the code:
#include <stdarg.h>
#include <stddef.h>
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__}) / sizeof(int))
#define EQI(...) ( \
alleqi(NUMARGS(__VA_ARGS__), __VA_ARGS__))
/* takes count number of int arguments */
int alleqi(size_t count, ...)
{
va_list va;
va_start(va, count);
int v0 = va_arg(va, int);
for (; count > 1; count--) {
if (v0 != va_arg(va, int)) {
break;
}
}
va_end(va);
return count == 1;
}
Please be advised the above only works for int arguments (and probably other types whose size is the same as int, though I am bracing for someone to accuse me of promoting undefined behavior if I advertise that!).
Thanks to this prior post for figuring out how to count arguments in a variadic macro: https://stackoverflow.com/a/2124433/4323

If you want to check six values, one approach would be to store them in an array
int a[6];
equals = 1;
for (int i=0; i<5; i++)
{
if (a[i] != a[i+1])
{
equals = 0;
break;
}
}

Approaches using arrays require you to change your data structure into an array.
Approaches using a variadic macro requires an additional function and function call (overhead).
Except for these two approaches, the only other way I see is to write them out. I feel the best way, or the more clear way, is to take the first variable and compare it to all other variables. By implication then either all variabes are equal, or at least two variables are unequal:
if ((a == b) && (a == c) && (a == d)
&& (a == e) && (a == f) && (a == g) ...)

Related

True and False with Operators

me again ... Sorry for asking maybe a little bit stupid questions but i am a starter and i really want to learn coding .. So i got a problem to realize why those are always true ? Its something with the operators or again C behavior is undefined. ?
int x;
int b;
b = 1 < x < 10;
printf("%d%d",b);
char c = 'z';
(c==' ') || (c='\t') || (c=='\n');
printf("%c",c);
Why those are always true ? Its because of ASCII code or what ?
Result of comparison of constant 10 with boolean expression is always true
You can see here a table for the C Operator Precedences
it could be read like this:
b = ((1 < x) < 10);
being that in languages such as C, relational operators return the integers 0 or 1, where 0 stands for false and any non-zero value stands for true.
so the value stored in b is 1 (true)
Also:
you're not initializing x, it should have trash info (probably != false)
and in your second code, you're allocating instead of comparing, (c='\t') is this on purpose? That's the reason it's printing a 'tab'.
In your first block of code, there are several problems:
x is uninitialized (you did not give it a value)
1 < x < 10 is not valid C
your printf statement expects 2 integer values to accompany the "%d%d", but you are only passing 1
I think this is what you want:
int x = <some valid value>;
int b;
b = ((1 < x) && (x < 10)); // expression is true if x is between [2..9]
printf("%d",b);
This line
(c==' ') || (c='\t') || (c=='\n');
Should be
(c==' ') || (c=='\t') || (c=='\n');
Note the double equals when comparing to \t (the tab character). Otherwise, you wind up assigning a tab char to c.

C languange 4 digit possible variations with exception

So i have a homework, but i can't wrap my head around why this code doesn't work.
Problem sounds something like this:
Make a code that checks all possible variations of 4 digit number, but there are no 3 same digits in a number. ( i hope that makes sense)
My code:
#include<stdio.h>
int main ()
{
int i;
char a,b,c,d;
for (i=0; i<9999; i++)
{
a = i/1000;
b = i/100%10;
c = i/10%10;
d = i%10;
if (a==b==c) {i++;}
else if (b==c==d) {i++;}
else if (c==d==a) {i++;}
else if (d==a==b) {i++;}
else if (a==b==c==d) {i++;}
else
{
printf("%d,%d,%d,%d\n", a,b,c,d);
}
}
}
I want it to print out something like this:
0,0,1,1
0,0,1,2
0,0,1,3
...
0,1,0,9
0,1,1,0
0,1,1,2
...
9,9,8,8
Instead it prints:
0,1,2,2
0,1,3,3
0,1,4,4
0,1,5,5
0,1,6,6
...
0,8,6,6
0,8,7,7
0,8,8,8
0,8,9,9
0,9,2,2
...
9,9,9,8
There's a problem with these comparisons:
if (a==b==c)
This doesn't find out if a, b and c are all the same. The result of == is 0 or 1, and then that is compared to the third number. So per example if all three numbers are 9, then 9==9==9 turns into 1==9, which is 0, so the if is not taken. What's more, you have false positives for things like 9==9==1.
What you instead need here is
if ((a==b) && (a==c))
Now you check if a is equal to b, and when it is, you check it with c, and the if is taken if they're all the same.
Likewise of course for the other comparisons, so instead of else if (a==b==c==d) you want else if ((a==b) && (a==c) && (a==d))
As other answers have noted, you can't chain comparison operators in C and get the expected results. Use logical operators to combine comparisons. It would probably be more clear to use || to avoid all of the else statements.
There is another significant problem with the posted code: i is incremented whenever a failing number is found. But then i is incremented again by the for loop. This causes the number after a failing number to be skipped, so some desired numbers will not be found. For example, 3222 should fail, and the subsequent number 3223 should pass, but this number is skipped by the posted code (after the comparison corrections), with the next number to be checked 3224. Instead, just use continue:
if ((a == b && a == c) ||
(b == c && b == d) ||
(c == d && c == a) ||
(d == a && d == b) ||
(a == b && a == c && a == d)) {
continue;
} else {
printf("%d,%d,%d,%d\n", a,b,c,d);
}
You can't use multiple equalities like this. You have to do them separately with and conditions (e.g. a==b && b==c).

K&R 1.6 Array. Not understanding the code [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I start reading the book K&R The C programmming ( 2nd edition). And I got stuck on the 1.6 Array; I just can't seem to figure out what the code does (even tho it says it counts digits, white spaces and others!). Here is the code:
#include <stdio.h>
/* count digits, white space, others */
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
printf("digits =");
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
printf(", white space = %d, other = %d\n",nwhite, nother);
}
So first it defines Integers, ( c,i,nwhite,nother);
After that it creates an array of 10 digits, ( 0 -9 )
After that it sets nwhite and nother to 0.
the for loops set I to 0, i < 10 means if its lower, add i = i + 1.
ndigit[i] = 0? I dont quite understand it, isnt i already is 0?
while ((c = getchar() != EOF) means What ever the input is and isnt at the end of the file?.
After that part I kinda got lost and I'm not sure what
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
Does at all.
And I don't quite understand why the for (i = 0; i < 10 ; +=i ) is repeated . I do understand English but some expensive use of words will confuse me. So if you dont mind, please keep it basic for me. I really hope there is someone out there who can help me understanding this code 100%. Because after all, who wants a programmer who cant even understand the code? :)
Let us step through the code and see what is happening.
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
In the first first line of code we are declaring[0] (to the compiler) that c, i, nwhite and nother will be integer variables. At this point, while we have declared these variables, we have not given them any value.
The next line we are declaring that ndigit will be an array of 10 integers, again no initialization is happening so we have no idea of what the value of those ten integers might be.
In the third line we are defining nwhite and nother to be zero, in other words we are initializing them to some value.
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
In this loop, we are initializing the variable i to be zero, and we will increment it by one ever time through the loop, till the value become ten or larger. The body of the loop sets each element of the array to zero. This is a common c-idiom for initializing the elements of an array.
while ((c = getchar()) != EOF)
{
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
}
The next block of code does the actual counting. While the code in K&R is syntactically correct, I prefer enclosing the bode of the while loop with curly-braces, I find it easier to read, but it is a personal thing [1].
The condition of the while loop ((c = getchar()) != EOF), can be kind of confusing. We perform the operation in parenthesis first, which is c = getchar() which has the effect of getting the next character and assigning it to the variable c. (remember that in C a character (i.e. variable of type char), is just a small integer so we can assign a character type to an integer type). The assignment statement has a return value[2], in that it returns the value on the right side of the assignment operator, so the operation in parenthesis returns the value of getchar(), which is then compared to EOF, and if it doesn't equal EOF we enter the body of the while statement.
The first if statement checks to see if the character is a number. In ASCII, number have the value of 0x30 ('0') through 0x39 ('9'), so we check to see if the character is in that range. If it is, we increment the appropriate value in the ndigit array. For example, suppose that we have read in the character '5' which has an ASCII value of 0x35. Because 0x35 is between 0x30 and 0x39 we have a digit. Performing the subtraction c - '0' is equivalent to 0x35 - 0x30 which equals 0x05. We then use this as the index into the array, and increment the appropriate value with ++ndigit[c-'0'].
The next branch of the if-block, check to see if c is a a white space, i.e. the
expression c == ' ' || c == '\n' || c == '\t' check to see if c is a space or if c is a new-line or if c is a tab. If c is one of those characters we then
increment nwhite.
Finally, the else branch is taken if we do not have a digit or white space, and we then increment nother.
printf("digits =");
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
printf(", white space = %d, other = %d\n", nwhite, nother);
}
The last bit of code just prints out the results. Because we want to look at all ten elements of the ndigit array, we need to step through the array again so we use the for loop structure to look at each element of the array.
Hopefully, this clears up some stuff. Something you may want to try is to modify this code so that it counts the of letters that are appearing in the input as well. First just try and count letters, with out regard to case, and then see if you can count upper and lower case letters.
notes:
[0] Declaring a variable is just specifying the name and type of the variable, so int x; is just a declaration. We are providing just enough information to the compiler that it can check our usage of x. A definition is when we assign a value to the variable, so x=5; is a definition. Note that the declaration and definition can be combined into a single line int x = 5;. At the assembly level, a declaration causes storage to be allocated for the variable, but does not set what the storage location contains.
[1] The C grammar says that the curly-braces are not needed for a while block if
it consists of a single statement, i.e.
while(n > 10)
c--;
and
while(n > 10)
{
c--;
}
are equivalent, I just find the second easier to read. Also, the C grammar
says that curly braces are not need for the body of an if statement if the body consists of a single statement, so for example
if(n < 10)
n = n - 10;
and
if(n < 10)
{
n = n - 10;
}
are equivalent.
Finally, the else if and end all are part of the if statement so the statement
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
is effectively a single statement, and thus why the curly braces are not needed.
Also, for readability and maintainability I tend to use curly braces with if / else if / else blocks - but again it is a personal think.
[2] The assignment statement has a return value of the left hand side, so a simple expression of a = 10; the return value is just ignored. Having a return value allows us to write something like, a = b = c = 10 which will have the effect of setting a, b and c to 10. In addition of having a return value, the assignment operator is right associative, so the above expression would be
interpreted as a = (b = (c = 10)).
-T.

Why the "if constraint" not working in the code?

The first if statement is not working and code is running without considering the constraint.
#include <stdio.h>
int main(void)
{
int with;
int inacbal;
float acleft;
scanf("%d",&with);
scanf("%d",&inacbal);
if(0<=with<=2000&&0<=inacbal<=2000) //this statement not working
{
if((with%5)==0)
{
if(inacbal>with)
{
acleft=(float)inacbal-(float)with-0.50;
printf("%.2f",acleft);
}
else
printf("%d",inacbal);
}
else
printf("%d",inacbal);
}
return 0;
}
Even on inputting value greater than the constraint relation the loop is running.
While mathematicians sometimes use the shorthand a < b < c, the C language is a bit more strict.
You must rewrite:
if(0<=with<=2000&&0<=inacbal<=2000)
to be something like:
if((0 <= with) && (with <= 2000) && (0 <= inacbal) && (inacbal <= 2000))
What you have actually is valid C but it does not do what you would normally expect. The expression 1 < 2 < 3 actually means: calculate 1 < 2 (giving the integral truth value 0 or 1 for false and true respectively) then comparing that against 3.
If you want to use a shorter form, you can use something like:
#define between(a,b,c) (((a) <= (b)) && ((b) <= (c)))
:
if (between (0, with, 2000) && between (0, inacbal, 2000))
though you need to watch out for duplicated side effects if you use terms such as a++ when using it. A safer approach may be replacing the macro with something along the lines of:
int between (int a, int b, int c) {
return (a <= b) && (b <= c);
}
You cannot compare avariable to two other values like that. You should separate the conditions:
if ((0<=with) && (with<=2000) && ( 0<=inacbal) && (inacbal<=2000))
The statement
if(0<=with<=2000&&0<=inacbal<=2000)
is not checking variables between the given range. These comparisons doesn't have mathematical meaning in C.
Compiler should raise a warning
[Warning] comparisons like 'X<=Y<=Z' do not have their mathematical meaning [-Wparentheses]
To check whether a value is between a given range or not you need to use && operator. You need to rewrite it as
if(0 <= with && with <=2000 && 0 <= inacbal && inacbal <=2000)

Assign and compare in a single statement in C

How can I convert the following code to a single line?
int *i;
i = some_func_ret_int_ptr();
if(!i)
{
// Do something
}
// Will use 'i' later
I want to do something like:
if((i=some_func_ret_int_ptr) && !i)
{
// Do something
}
// Will use 'i' later
But I am wasting one comparison here. Is there a better way to do it?
All I want is assignment and comparison in the if and compare only i.
With C, this is as far as you can golf it:
int *i;
if(!(i = some_func_ret_int_ptr()))
{
// do something
}
// Will use i later
In addition to what is suggested in other answers, you can also do it as
if (i = some_func_ret_int_ptr(), !i)
{
// Do something
}
It is a literal implementation of what you had originally, with the statement sequence replaced with an expression sequence separated by the , operator.
It does not make much practical sense, though.
You can do
if(!(i = some_func_ret_int_ptr()))
{
...
}
What happens in this code, in order, is:
The return value of some_func_ret_int_ptr() is assigned to i
The statement !i is checked
If i == 0 what's inside the if gets executed, otherwise it will not
Clean and readable:
int * i = some_func_ret_int_ptr();
if (!i) { /* ... */ }
An option not mentioned yet is:
if ( NULL != (i = some_func()) )
Using the explicit comparison against NULL makes it very easy to read the intent of this code. Especially considering that your function probably won't have ret_int_ptr in its name.
Using the #include <ctype.h> standard library, to get the toupper(char) function, we can write the following function:
void StringToUppercase(char* str)
{
for (int i=0; (str[i] = toupper(str[i])) != 0; i++); // No for-loop body!
// The expression "(str[i] = toupper(str[i]))" executes first and then returns str[i]
}
so that the statement (str[i] = toupper(str[i])) != 0; both assigns a char and checks to see if it is '\0' or not.
The way this works is that part of the C language specifies that assignment expressions have the value of the lefthand expressions after the assignment. For example, with ints, consider the following code snippet:
int x = 5;
int y = x = 8;
// Assignment operators (= += <<=) have right-to-left associativity.
// The expression `(x=8)` returns the value 8, after it has been executed
int z = x != y; // Comparisons have greater (tighter) precedence than assignment
printf("(x, y, z) = (%d, %d, %d)\n", x, y, z); // prints (8, 8, 0)
Same as M.M's answer, but I would go with:
if ((i = some_func_ret_int_ptr()) != NULL)
As it makes the execution order clearer.

Resources