Skip to main content

Logical Operators

When looking at conditions used in the control structure checks, we often use comparison operators. We often think of these operators as being true or false. However, in C, there was never a true boolean data type like there are in other languages. While you can make use of a library called stdbool.h to create variables that feel like they are boolean types, it is not neccessary to do so as long as you understand the nature of truthy and falsey. In the notes, we will simply make use of the way that C has traditionally handled true and false values.

Comparison Operators

Comparison operators can be used to compare any basic data type. Typically we think of the result of these operations as either truthy or falsey.

This table shows the comparison operators that we use. In this table assume the following variable declaration and initialization:

	int x = 5;
operator nameoperator symbolwhat it doesexample
equivalence==a == b is truthy if a is the same as bx == 5 is truthy
x == 10 is falsey
not equivalent!=a != b is truthy if a is not the same as bx != 5 is falsey
x != 10 is truthy
less than<a < b is truthy if a is smaller than bx < 10 is truthy
x < 5 is falsey
greater than>a > b is truthy if a is bigger than bx > 5 is falsey
6 > x is truthy
less than or equal to<=a <= b is truthy if a is smaller or equal to bx <= 5 is truthy
x <= 6 is falsey
greater than or equal to>=a >= b is truthy if a is bigger or equal to bx >= 5 is truthy
x >= 4 is falsey
tip

One of the most difficult to find errors involve the assignment (=) and equivalence (==) operators. In math, we have traditionally used the = symbol to mean both. In C, there is a clear distinction. They are very much not the same. To help avoid errors between these, try reading the = operator as assignment and == operator and equivalent or same as. For example, read the statements as described in the comments:

x = 5  //"x is assigned 5"
y == 5 //"y is equivalent to 5" or "y is the same as 5"

The point is to distinguish between these operators clearly.

Boolean Operators

Aside from the comparison operators, there are also a number of boolean operators that allow us to make more complex statements by connecting multiple comparisons.

And - &&

The and operator is written using the symbol &&. This expression is truthy if both operands are truthy. This expression is falsey if both expressions are falsey

The following is a truth table and shows the result of an and operation on two variables A and B

ABA && B
TTT
TFF
FTF
FFF

Or - ||

The or operator is written using the symbol ||. This expression is truthy if either operands are truthy. This expression is falsey if both expressions are falsey

The following is a truth table and shows the result of an and operation on two variables A and B

ABA || B
TTT
TFT
FTT
FFF

Not - !

The not operator is written using the symbol !. It is a unary operator. This expression is truthy if operand is falsey. This expression is falsey operand is truthy

The following is a truth table and shows the result of the not operation on two variable A

A!A
TF
FT

Common Use Cases

There are some common use cases for using comparisons. We will outline a few here to explain how you can string together multiple comparisons with boolean operators to form an expression that performs these type of checks

X is either a or b

Sometimes we want to see if x is one value or another. For example in our bubble tea example, we asked the user to enter Y or N. In the check to see if it is Y, we only check capitals, but what if we also wanted to accept lower case?

One way we could do this is to use the or || operator


x == 'Y' || x == 'y'

X is between a and b inclusive

Suppose we want to test a variable x to see if it is a value between a to b inclusive. That is, there are two values a and b where a < b. We want to know if x is between these two values.

Here is a visual representation of the situation. The top arrow in pink represents all values that are larger than or equal to a, the bottom arrow in blue represents all values smaller than or equal to b. If we want something in between a and b, we want both of those things to be true. The part where there both arrows exist is that portion of numbers where its both.

Our expression is therefore a test that checks if x is larger than the a value AND also smaller than the b at the same time.

 x >= a && x <= b

This is the type of expression we used in our transit fare problem to check ages

X is outside of the range a and b

Suppose we want to test a variable x is outside of the range between a to b inclusive. That is, there are two values a and b where a < b. We want to know if x is outside of the range of these values.

This is essentially the opposite of the previous example of x being between a and b inclusive. We want the situation where it isn't between.

One of the simple ways to do this is employ the not (!) operator.

!(x >= a && x <= b)

Alternatively, you can also look at it as the parts that are outside of that range.

Notice how the comparison is opposite to what it was previously was and the use of the || operator. This equivalency of expression follows what is called De Morgan's Law:

(x < a || x > b)

De Morgan's Law

De Morgan's law refers to a transformation of an expression that uses an and operation to one using an or operation.

We saw in the previous set of examples that we can write the same expression in two different ways. It is simply a matter of how you view the world.

Suppose we have two expressions that we call A and B. These expressions evaluate to truthy or falsey.

What De Morgan's Law states is that

!(A && B) is the same as !A || ! B

Also

!(A || B) is the same as !A and !B

For example in our previous example, we had this expression:

!(x >= a && x <= b)

so, in this case, according to de Morgan's Law, we can rewrite this as:

(x < a) || (x > b)

Now, x < a is basically !(x >= a) (think of it as opposite of original) Similarly x > b is basically !( x <= b)

Thus, we are applying De Morgan's law to our original expression.

De Morgan's is useful because sometimes it is easier to write it one way vs another. Using this law, we have options on how to put together our expressions

Truthy vs Falsey

Throughout this chapter, we have used the term truthy vs falsey to describe the true and false. In C, there is no true boolean type. Instead, it actually uses numbers to indicate truthy vs falsey. For C, zero (0) is falsey. Every other value is considered to be truthy.

This can actually be both useful and troublesome. It can lead to some really unintended side effects also.

Consider for example the following block of code.

if (x = 0){
printf("in here!\n");
}

In this block of code, under what condition will we perform the printf()?

The answer is... nothing. it won't matter what x is, we will never perform the printf().

Now, why would this be? the reason is because we used the assignment operator in the if statement. Some compilers will warn you that this might be an error, but some will let you do this without any warning. Note that this is not an error... it is syntactically correct.

now, recall that for assignment, the result of an assignment is the value stored into the variable. This means that x = 0 results in 0. 0 is considered to be falsey so this expression is considered to be falsey.

This definition of truthy and falsey also allows us to form expressions such as:

if (x + y){
...
}

The above is equivalent to:

if( x + y != 0){
...
}