Search

2.6 — Boolean values and an introduction to if statements

In real-life, it’s common to ask or be asked questions that can be answered with “yes” or “no”. “Is an apple a fruit?” Yes. “Do you like asparagus?” No.

Now consider a similar statement: “Apples are a fruit”. Is this statement true or false? It’s clearly true. Or how about, “I like asparagus”. Absolutely false (yuck!).

These kinds of sentences that have only two possible outcomes: yes/true, or no/false are so common, that many programming languages include a special type for dealing with them. That type is called a boolean type.

Boolean variables

Boolean variables are variables that can have only two possible values: true (1), and false (0).

To declare a boolean variable, we use the keyword bool.

To initialize or assign a true or false value to a boolean variable, we use the keywords true and false.

Just as the unary minus operator (-) can be used to make an integer negative, the logical NOT operator (!) can be used to flip a boolean value from true to false, or false to true:

Boolean values are not actually stored in boolean variables as the words “true” or “false”. Instead, they are stored as integers: true becomes the integer 1, and false becomes the integer 0. Similarly, when boolean values are evaluated, they don’t actually evaluate to “true” or “false”. They evaluate to the integers 0 (false) or 1 (true).

Consequently, when we print boolean values with std::cout, std::cout prints 0 for false, and 1 for true:

Outputs:

1
0
0
1

If you want std::cout to print “true” or “false” instead of 0 or 1, you can use std::boolalpha:

This prints:

1
0
true
false

You can use std::noboolalpha to turn it back off.

A first look at booleans in if-statements

One of the most common uses for boolean variables is inside if statements. If statements typically take the following form:

if (expression) statement1;

or

if (expression) statement1;
else statement2;

When used in the context of an if statement, the expression is sometimes called a condition or conditional expression.

In both forms of the if statement, expression is evaluated. If expression evaluates to a non-zero value, then statement1 is executed. In the second form, if expression evaluates to a zero value, then statement2 is executed instead.

Remember that true evaluates to 1 (which is a non-zero value) and false evaluates to 0.

Here’s a simple example:

prints:

The condition is true

Let’s examine how this works. First, we evaluate the conditional part of the if statement. The expression “true” evaluates to value 1, which is a non-zero value, so the statement attached to the if statement executes.

The following program works similarly:

prints:

b is false

In the above program, when the condition evaluates, variable b evaluates to its value, which in this case is false. False evaluates to value 0. Consequently, the statement connected to the if statement does not execute, but the else statement does.

Executing multiple statements

In a basic form of an if statement presented above, statement1 and statement2 may only be a single statement. However, it’s also possible to execute multiple statements instead by placing those statements inside curly braces ({}). This is called a block (or compound statement). We cover blocks in more detail in lesson 4.1 -- Blocks (compound statements).

An if or if-else using multiple statements takes the form:

if (expression)
{
    statement1a;
    statement1b;
    //  etc
}

or

if (expression)
{
    statement1a;
    statement1b;
    // etc
}
else
{
    statement2a;
    statement2b;
    // etc
}

For example:

This prints:

The condition is true
And that's all, folks!

A slightly more complicated example

The equality operator (==) is used to test whether two integer values are equal. Operator== returns true if the operands are equal, and false if they are not.

Here’s output from one run of this program:

Enter an integer: 4
The value is non-zero

Let’s examine how this works. First, the user enters an integer value. Next, we use operator== to test whether the entered value is equal to the integer 0. In this example, 4 is not equal to 0, so operator== evaluates to the value false. This causes the else part of the if statement to execute, producing the output “The value is non-zero”.

Boolean return values

Boolean values are often used as the return values for functions that check whether something is true or not. Such functions are typically named starting with the word is (e.g. isEqual) or has (e.g. hasCommonDivisor).

Consider the following example, which is quite similar to the above:

Here’s output from one run of this program:

Enter an integer: 5
Enter another integer: 5
5 and 5 are equal

How does this work? First we read in integer values for x and y. Next, the conditional expression “isEqual(x, y)” is evaluated. This results in a function call to isEqual(5, 5). Inside that function, 5 == 5 is evaluated, producing the value true (since 5 is equal to 5). That value is returned back to the caller. Since the conditional evaluated to true, the statement attached to the if executes, producing the output “5 and 5 are equal”.

Boolean values take a little bit of getting used to, but once you get your mind wrapped around them, they’re quite refreshing in their simplicity!

Non-boolean conditionals

In all of the examples above, our conditionals have been either boolean values (true or false), boolean variables, or functions that return a boolean value. What happens if your conditional is an expression that does not evaluate to a boolean value?

You already know the answer: If the conditional evaluates to a non-zero value, then the statement associated with the if statement executes.

Therefore, if we do something like this:

This will print “hi”, since 4 is a non-zero value.

Inputting boolean values

Inputting boolean values using std::cin sometimes trips new programmers up.

Consider the following program:

Enter a boolean value: true
You entered: 119

Wait, what?

It turns out that std::cin only accepts two inputs for boolean variables: 0 and 1 (not true or false). Any other inputs will cause std::cin to silently fail. In this case, because we entered “true”, std::cin silently failed and didn’t assign a value to b. Consequently, when std::cout printed a value for b, it printed whatever uninitialized value was in variable b. Garbage!

Quiz

1) A prime number is a whole number greater than 1 that can only be divided evenly by 1 and itself. Write a program that asks the user to enter a single digit integer. If the user enters a single digit that is prime (2, 3, 5, or 7), print “The digit is prime”. Otherwise, print “The digit is not prime”.

Hint: Use if statements to compare the number the user entered to the prime numbers. Use a boolean to keep track of whether the user entered a prime number or not.

Quiz answers

1) Show Solution

2.7 -- Chars
Index
2.5 -- Floating point numbers

484 comments to 2.6 — Boolean values and an introduction to if statements

  • Hannes Wadman

    Is this program okay or is it too inefficient? (This by the way is "Prime.cpp" and is called by main in my "learning.cpp" program.) Also fmod is as I understand it more or less % for floats I hope that's correct! Also how would one go about making numbers bigger than -(2^64)/2 and (2^64)/2-1(The shitty computer I'm on currently has double long as 8 bytes) and precision in floats longer than 16 digits? Thanks in advance!

    • Hi Hannes!

      > Also fmod is as I understand it more or less % for floats
      It is. If you have questions about what a standard function does, documentations are your friend.
      https://en.cppreference.com/w/cpp/numeric/math/fmod
      http://www.cplusplus.com/reference/cmath/fmod/
      Use @std::fmod instead of @fmod

      > Also how would one go about making numbers bigger
      There's no standard way of doing this. You'll have to write your own number type. You should be able to do this after bit-wise-operations and classes have been covered.

      > Is this program okay or is it too inefficient?
      * Initialize your variables with uniform initialization
      * Use double literals when calculating with doubles (1.0 instead of 1 and so on)
      * Perform simple checks first. Run line 13/17/23/27 before calling @fmod. Conditions in line 39/43 should be swapped.
      * Line 17 can be written as if (p < 0.0), since all numbers in (0.0, 1.0] have already been checked for.
      * Line 39: Calculate p/2.0 once. That way you don't have to calculate 2.0*n in every cycle.
      * Line 41: n += 2
      * Variable names should be descriptive. Use single-letter names for iterators only. "p" could be "dbUserInput", "n" should be "i".

      • Hannes Wadman

        Thank you very much! Just a few more follow up questions 🙂
        These will ask questions in order of appearance in the list you sent!

        * I'm assuming all the points in the list are things that could be more efficient, however I'm pretty sure the only variable I had to initialize(n) was initialized with uniform initialization in row 38. Should p also be initialized here just to make sure I avoid undefined behaviour or were you pointing out something else?

        * I looked up the links you sent me and it looks like a double fmod will always use two double floats. How did my code work with long double fmod(which I couldn't properly do before but I assume after reading the link it's just fmodl. Visual Studio seemed to make it into long double fmod for me in the code above though when I hover over it with my mouse) when I didn't define the literal as long double fmod? When I just write 2 and not 2l or 2f I'm going to assume it's automatically made into an int or a double, but the code seemed to work fine anyways. Why does this happen since we normally have to define the literals when assigning them to variables?

        * I'm assuming this is more efficient because we won't always have to make the "hard"/demanding calculations every time we run the code since we might be able to end the function before we get to that part if it's even, negative etc. I was just wondering if we assume one case is gonna be very uncommon in relation to the other cases e.g entering a negative number vs entering an even number, we should put the function calculating whether the number is before the one testing whether it's negative or not. Also even though entering a number like 1083 that is not negative, not a decimal, not even, not one or 0 is way more likely than entering a negative number I'm assuming we still put the function testing if the number is smaller than 1(which I'm gonna change to smaller than 0) since it's just so much less demanding than testing if it's divisible by 3, 5, 7 and so on. Is all of this correct? How would you order them?
        If I swap the conditions and let's say p = 20 and n = 3 it will just skip the while function go into if and if will fail and it will print p is prime even though it's not prime. I feel like I'm misunderstanding what you meant horribly but since you only said conditions I assume you didn't mean the while and if as well, but even then it won't work right?

        * I will make sure to do that! Will this improve performance slightly?

        * Will it remember that p / 2 has been calculated as well that p hasn't been changed and not calculate it again?

        * I will change this too, but I'm wondering if the change is more efficient or is it just "best practice" since it's more commonly used(assumption)?

        * I see I'm already falling into the pitfalls "I won't change this whatever let's just use random numbers" :). Well better to make mistakes sooner than later! Should n be i for any specific reason however?

        Thank you SO MUCH! I really appreciate you helping me even though you're under absolutely no obligation.

        • > Should p also be initialized
          Always initialize everything. This way you won't ever forget to initialize a variable that has to be initialized and your program will be in a well defined state at any point in time. If you're certain about what you're doing you can drop some initializations in favor of efficiency.

          > fmod
          Version (4) of @std::fmod on cppreference:

          @Arithmetic1 and @Arithmetic2 can be turn into any arithmetic type, because they are templates. Templates are covered later.

          > efficiency
          You got a point there. You have to weigh between how difficult it is to evaluate a condition and how likely it is to even get there.

          > it will just skip the while
          I was worried about my statement being ambiguous. I didn't mean swap the lines, but swap the conditions in each line.

          And the same for the if. Again, the reason being that the multiplication is faster than calling @std::fmod. And again, one could argue about likeliness of one condition failing before the other.

          > Will this improve performance slightly?
          Assuming your compiler didn't optimize your current version, yes.

          > Will it remember that p / 2 has been calculated
          It might, but you should make sure it does by introducing a temporary.

          > I'm wondering if the change is more efficient or is it just "best practice"
          There should be no difference after compilation. += is faster to read and easier to update (If you decide to rename the variable eg.).

          > Should n be i for any specific reason however?
          Single letter, because it's an iterator. 'i', because it's an int. If you have nested loops (Loop in a loop), one continues naming the next iterators alphabetically. Like one would do in maths. i -> j -> k ...

          > Thank you SO MUCH!
          You're welcome 🙂

          • Hannes Wadman

            One last thing! I know I'm asking a lot of questions.
            By using 0.0 instead of 0 am I not taking up more space since one is an int(4 bytes on my system) and one is a double(8 bytes on my system)? Or will the templates take up the full 8 bytes anyways if it's a double fmod for example?

            • The int has the be promoted to a (long) double before any calculations can be performed with another (long) double.
              The problem with using ints where you want doubles is that, at some point, you'll forget to use a double when you have to. Always use the appropriate types and you won't run into this.

  • Anon

    Thanks =]

    • Hi Anon!

      * Line 2: Don't use "using namespace".
      * Line 6, 8, 18, 20: Initialize your variables with uniform initialization.
      * Line 6: @x cannot be divisible by anything bigger than (x / 2).
      * Line 8, 9 and 20, 21: Unnecessary temporary
      * Poor variable names. Variable names should be descriptive.

  • Hue Saki

    hey there/
    this works fine in mine code block

    int main()
    {
        bool b; // uninitialized variable
        std::cout << "Enter a boolean value: ";
        std::cin >> b;
            std::cout << "You entered: " << b;

        return 0;
    }

  • jeron

  • George

    Great lesson! I was wondering, how would the program in the quiz be written if one wanted to include all prime numbers and not just single digits?

    • You'd have to write an algorithm to either calculate prime numbers, or write an algorithm to detected weather or not a given number is prime, then walk through all numbers and print only those for which the algorithm decides that the number is prime.
      You'll learn how to do this in later lessons.

    • jeron

  • bbducky

    Just wanted to say that this quiz was really confusing.  I missed the "single integer" part and thought I needed to come up with a program that would tell you whether or not ANY number entered was prime, and after banging my head against the wall for like 30 minutes I just gave up lol.  Even after I realized the problem though,  I still struggled.  This is what I initially tried and I don't understand why it doesn't work if I write my main loop like this:

    Why do I need to create another bool called prime and then use that instead of just plugging isPrime directly?  If anyone could help explain that would be great as I'm super confused...

    • Hi bbducky!

      In line 5 you're calling @isPrime, passing the variable @x. @isPrime returns a boolean, which you're not storing anywhere, it is discarded.
      Line 7 will always be true, because functions are always non-null (You'll learn more about this later).

      * Line 2: Initialize your variables with uniform initialization
      * Line 10, 15 should be moved outside of the conditional blocks, because they are independent of the condition.

      References
      Lesson 1.4 - A first look at functions and return values

  • Hello!
    I figured out the issue. Posting the correct program below. I thought it was something to do with the (x == 2, 3, 5, 7). I went back to 2.1 and saw that each integer had to have a something attached.

    INCORRECT

    CORRECT

    • Hi Adrian!

      > CORRECT
      If you had read the compiler warnings or tested your code, you'd know that it is incorrect.
      The comma operator will execute all members, but it discards all values except the last one (x == 7). Your @isPrime function only returns true if @x is 7, false otherwise.
      Have a look at Alex' solution.

  • Dan

    Hi,

    Can you explain the reason behind return false;? I understand that it's meaning is to return a false value, but does the compiler know this as like an invisible else statement?

  • Hi Flux!

    Working, congrats, but

    * Line 10: Initialize your variables with uniform initialization
    * Line 14, 16, 18, 20: Don't repeat yourself, this is what the boolean mentioned in the quiz is for.

    Try to come up with a solution with less repeated code to make sure you understood booleans.

    • Flux

      Oh hi, I've seen you on lots of posts. It's an honor to have you reply. 🙂 To celebrate, I've made the changes you noted and, as an added bonus, an attempt at input validation using just the tools covered up to 2.6

      • Good job!

        Two things,
        1. @isValid isn't used
        2. When you have a conditional statement which exceeds one line, wrap it in curly braces. (Line 18-22)

        • Flux

          Good eye, it surely was not used. That changed the amount of statements attached to that if, so hopefully I've formatted it correctly.

  • Flux

    Here's my less elegant, less readable nested solution.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]