Loops

  • A loop is a very powerful programming construct that is used when we want to do something multiple times.

  • There are three kinds of loops in C++:

    • For loops

    • While loops

    • Do while loops

    Do while loops are just like while loops, except that checking the condition happens after the execution of the block of code inside the loop’s body. They are used less often than while loops and for loops, so we don’t require you to know do while loops in EECS 183.

While loops

  • While loops are of this form:

    int i = 0; (1)
    while (i < 10) (2)
    { (3)
        cout << "hi" << endl;
        i++; (4)
    }
    1 Initialization of the variable used to control the loop’s execution.
    2 Condition that has to be true for the loop to continue executing. If the condition is fall, the body of the does not execute.
    3 The body of the loop is marked by curly braces ({}). After the body, the condition will be again checked.
    4 The update of the loop variable usually takes place at the end of the body.

    The above example prints hi followed by a new line ten times.

  • Let’s do a more complicated example.

    Write a program that asks the user for a positive integer and keeps asking until the user cooperates. The program should behave per the sample output below, wherein red underlined text represents some user’s input:

    Please give me a positive integer: 0
    Try again: -42
    Try again: 183
    Thanks for the 183!

    Solution:

    positive-0.cpp
    #include <iostream>
    using namespace std;
    
    int main(int argc, const char * argv[])
    {
        cout << "Please give me a positive integer: ";
        int n;
        cin >> n; (1)
        while (n < 1) (2)
        {
            cout << "Try again: ";
            cin >> n; (3)
        }
        cout << "Thanks for the " << n << "!" << endl;
    }
    1 Read an integer into n.
    2 Do the following so long as n is less than 1…​
    3 Read another integer into n. This is the update of the loop.

For loops

  • Now let’s look at for loops. They’re similar in structure to while loops: they also have an initialization, a condition, a body and an update. However, for loops group the initialization, the condition and the update on one line.

  • This loop again prints hi followed by a new line ten times.

    for (int i = 0; i < 10; i++)   (1) (2) (4)
    { (3)
        cout << "hi" << endl;
    }
    1 First, int i = 0 initializes the variable i that controls the loop.
    2 Then, the condition i < 10 is checked. It is checked each time before the body of the loop executes.
    3 Curly braces ({}) mark the start and the end of the body of the loop, which executes on each iteration.
    4 i++ is the update of the loop that executes each time after the body and before the condition.

For vs. While

  • What’s the difference between for loops and while loops?

    • Not much difference! In fact, you can always rewrite a for loop as a while loop and vice-versa. Let’s take a look at the earlier example again:

      int i = 0; (1)
      while (i < 10) (2)
      { (3)
          cout << "hi" << endl;
          i++; (4)
      }
      for (int i = 0; i < 10; i++)   (1) (2) (4)
      { (3)
          cout << "hi" << endl;
      }
      1 Initialization (outside of the while loop and inside the for loop).
      2 Condition (always checked after the body executes).
      3 The body of the loop is marked by curly braces ({}).
      4 Update (inside the body of the while loop and outside of the body of the for loop).
    • The major difference between the while loop and the for loop above is that i is declared outside the while loop, but inside the for loop. This means that i will still be in scope after the while loop. However, i cannot be used after the for loop.

  • When should you use for loops and when should you use while loops?

    • It’s up to you! After getting comfortable with loops, you’ll most likely have a preference for one or the other.

    • In general, use while loops for event-controlled loops (i.e. if you want a block of code to execute so long as something hasn’t happened).

    • And use for loops when you want a block of code to be executed n number of times.

More Examples

  • Let’s write a program that counts down from 5 to 1. We can use either a while loop or a for loop. Here, I’m using a for loop.

    Solution:

    countdown.cpp
    #include <iostream>
    using namespace std;
    
    int main()
    {
        for (int i = 5; i > 0; i--)
        {
            cout << i << endl;
        }
    
        cout << "BLAST OFF!!!" << endl;
    }

    And here’s the output of this program:

    5
    4
    3
    2
    1
    BLAST OFF!!!
  • This program tries to print 10 stars, but fails to do so correctly. Can you find the bug?

    buggy-2.cpp
    #include <iostream>
    using namespace std;
    
    int main()
    {
        for (int i = 0; i <= 10; i++)
        {
            cout << '*';
        }
    }

    The problem is that this program prints 11 stars, not 10. This is because i starts at 0. After the body executes for the first time, i is incremented and i 1. After the body executes ten times, i is 10. The condition i ⇐ 10 is still true and the body executes for the eleventh time. Then i is incremented again and becomes 11, after while the condition i ⇐ 10 is false and the loop stops.

    To fix the bug, change the condition from i ⇐ 10 to i < 10.

  • And another example of a buggy program. It tries to print print 10 stars, one per line. However, it prints 10 stars on the same line. Can you figure out why?

    buggy-3.cpp
    #include <iostream>
    using namespace std;
    
    int main()
    {
        for (int i = 0; i < 10; i++)
            cout << '*';
            cout << endl;
    }

    The problem is that the curly braces are missing and do not surround the body of the loop. And so in this case, only the first statement is considered to be the body of the loop:

    cout << '*';

    Remember that C++ does not care about whitespace and that indentation is only used for human readability. So even though the line

    cout << endl;

    is indented, it is not considered to be part of the loop’s body, since it’s not inside curly braces.

  • Loops can also be nested. Can you figure out what the following code prints?

    for (int row = 0; row < 3; row++)
    {
        for (int col = 0; col < 4; col++)
        {
            cout << 'x';
        }
        cout << endl;
    }

    Answer:

    xxxx
    xxxx
    xxxx

ASCII

  • Recall that everything inside the computer is represented in 0s and 1s (binary). That means that everything, even chars and strings are represented as integers under the hood.

  • ASCII is an encoding system which represents every character with a given number. For example, an uppercase A is represented by the number 65 and an uppercase Z is represented by the number 90.

  • Here’s a glimpse of the ASCII table that illustrates the correspondence between characters and numbers that represent them:

    ascii

  • You should try to memorize all the ASCII values. However, you should know the following:

    • There is an integer corresponding to each character in the ASCII table.

    • Uppercase letters are next to each other in the ASCII table.

    • Lowercase letters are next to each other in the ASCII table.

    • A has a value of 65 and a has a value of 97, so uppercase letters come before lowercase letters.

    • The character 0 does not have an ASCII value of 0. In other words, the character 0 is not represented with the number 0.

  • Let’s now write a program that prints all the English letters in the alphabet (first, uppercase A–Z, and then lowercase a–z), along with their ASCII values. The program should print something like this:

    A: 65
    B: 66
    C: 67
    ...
    
    a: 97
    b: 98
    c: 99
    ...
  • Here’s one way to do it:

    ascii-0.cpp
    int main()
    {
        // mapping for uppercase letters
        for (int i = 65; i < 65 + 26; i++) (1)
        {
            cout << (char) i << ": " << i << endl; (2)
        }
    
        cout << endl;
    
        // mapping for lowercase letters
        for (int i = 97; i < 97 + 26; i++) (3)
        {
            cout << (char) i << ": " << i << endl;
        }
    }
    1 We start the first loop at 65 (the ASCII value of A) and execute the loop 26 times (once per letter), so long as i is less than 98. (97 is the ASCII value of Z).
    2 Inside the body of the first loop, we print the ASCII value after printing the corresponding character that we get by casting the integer with the ASCII value to a char.
    3 Similarly, we have a for loop for lowercase letters that starts at 97 (the ASCII value of a) and executes 26 times.

    However, ascii-0.cpp has a lot of magic numbers (65, 26, 97). And to implement it correctly, you’d have to remember, for example, that a corresponds to 97.

  • It turns out that we can also cast from chars to ints, so let’s write a second version of that program, where we avoid magic numbers:

    ascii-1.cpp
    #include <iostream>
    using namespace std;
    
    int main()
    {
        // mapping for uppercase letters
        for (char c = 'A'; c <= 'Z'; c++) (1)
        {
            cout << c << ": " << (int) c << endl; (2)
        }
    
        cout << endl;
    
        // mapping for lowercase letters
        for (char c = 'a'; c <= 'z'; c++) (3)
        {
            cout << c << ": " << (int) c << endl;
        }
    }
    1 We iterate over chars, starting at A up until Z. We can also increment c on each iteration, and we’ll get the next character in the ASCII table.
    2 Each time, we print the character, and then its ASCII value that we get by casting the char to an int.
    3 Similarly we iterate over chars from a to z.

    Notice how now in ascii-1.cpp, we don’t have to now the exact values of A, Z, a or z

  • Being able to represent characters with numbers gives us the ability to manipulate them, which opens lots of possibilities (e.g. capitalizing strings). More on this in a week or so!

Battleship

  • Write a program that prints this Battleship board using loops. Take care to ensure that all spaces match this example:

       1  2  3  4  5  6  7  8  9  10
    A  o  o  o  o  o  o  o  o  o  o
    B  o  o  o  o  o  o  o  o  o  o
    C  o  o  o  o  o  o  o  o  o  o
    D  o  o  o  o  o  o  o  o  o  o
    E  o  o  o  o  o  o  o  o  o  o
    F  o  o  o  o  o  o  o  o  o  o
    G  o  o  o  o  o  o  o  o  o  o
    H  o  o  o  o  o  o  o  o  o  o
    I  o  o  o  o  o  o  o  o  o  o
    J  o  o  o  o  o  o  o  o  o  o
  • Since it’s a lot easier to print top to bottom, we’ll print the board row by row.

    So first, let’s print the top row of numbers. All we need is a single for loop that prints numbers 1 through 10 separated by spaces:

    for (int i = 1; i <= 10; i++)
    {
        cout << i << "  ";
    }

    Now we need to print ten rows of holes, with letters in the leftmost column. Let’s start by just printing a single row of 10 holes:

    for (int i = 0; i < 10; i++)
    {
        cout << "o  ";
    }

    To print ten such rows, we’ll need to put the above loop inside another loop. And we’ll need to go to a new line after the inner loop executes to separate each row.

    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            cout << "o  ";
        }
        cout << endl;
    }

    Finally, we need to print the corresponding letter in each row. We can do that by printing the character that we get after adding i (a number from 0 to 10, corresponding to the row) to the character A when we print each row.

    // print rows of holes, with letters in leftmost column
    for (int i = 0; i < 10; i++)
    {
        cout << (char) ('A' + i) << "  ";
    
        // print 10 holes
        cout << endl;
    }

    Also, let’s define a constant to avoid magic numbers

    const int BOARD_SIZE = 10;

    And replace 10 with BOARD_SIZE.

  • Here’s the full solution:

    battleship.cpp
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
    #include <iostream> using namespace std; int main() { const int BOARD_SIZE = 10; // print top row of numbers cout << " "; for (int i = 1; i <= BOARD_SIZE; i++) { cout << i << " "; } cout << endl; // print rows of holes, with letters in leftmost column for (int i = 0; i < BOARD_SIZE; i++) { // letter cout << (char) ('A' + i) << " "; // holes for (int j = 0; j < BOARD_SIZE; j++) { cout << "o "; } cout << endl; } }

Project 2

  • Some parts of Project 2 involve working with numbers. You might have to determine if one number is divisible by another, be able to get the first 2 digits or a number and be able to get the last 2 digits of a number.

  • How to determine if a is divisible by b?

    Remember that the modulo (%) operator gives us the remainder of dividing two numbers. So if a is divisible by b, it must be the case the a % b is 0.

  • How to get the first n digits of a number?

    To get the first digit of 123, divide 123 by 100 (you’ll get 1, since 1.23 will be truncated to 1 during integer division). To get the first two digits of 123, divide 123 by 10.

    To get the first digit of 1234, divide 1234 by 1000. To get the first two digits of 1234, divide 1234 by 100. To get the first three digits of 1234, divide 1234 by 1000.

    See the pattern?

    In general, if a is a number of k digits, you can get the first n digits of a if you divide a by 10^(k - n). Note that 10^(k - n) is not valid C++ syntax.

  • How to get the last n digits of a number?

    To get the last digit of 123, get the remainder after dividing 123 by 10. In other words, 123 % 10 will give you the last digit (3). Similarly, to get the last two digits of 123, do 123 % 100.

    To get the last digit of 1234, you need 1234 % 10. To get the last two digits of 1234, do 1234 % 100. To get the last three digits of 1234, do 1234 % 1000.

    And the pattern continues.

    Generally, if a is a number of k digits, you can get the last n digits of a if you mod a by 10^(k - n). Note that 10^(k - n) is not valid C++ syntax.