6: More Loops

What We Will Cover


Continuations

Questions from last class?

  • Exam reminder
  • What will be printed after the following C++ statements have executed?
    int count = 1;
    while (count <= 3) {
        cout << count << " ";
        count++;
    }
    
    1. 1 2
    2. 1 2 3
    3. 2 3
    4. 1 2 3 4

Homework Questions?

6.1: More About Loops

Learner Outcomes

At the end of the lesson the student will be able to:

  • Use sentinel values to terminate a loop
  • Describe the advantages of using a Boolean variable to control a loop
  • Use do-while statements to repeat sections of code
  • Develop strategies for processing input and handling errors

6.1.1: Indefinite Loops

  • Recall our looping application that simulated the play of an exciting game
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

int main() {
    char repeat = 'y';
    while ('y' == repeat) {
        cout << "\nPlaying an exciting game!\n";
        cout << "Do you want to play again? (y/n) ";
        cin >> repeat;
    }
    cout << "\nThanks for playing!\n";

    return 0;
}
  • Loops of this type are called indefinite loops because we do not know in advance how many time the loop will execute
  • Instead, the loop executes until some condition is satisfied
  • This behavior is different from a counting loop where we know how many times the loop will execute before the loop starts
  • Most problems solved with indefinite loops make use of while statements

While loop flow chart

Check Yourself

  1. True or false: with an indefinite loop, you often know in advance how many times the loop will repeat.
  2. True or false: the best looping statement for an indefinite loop is a for statement.
  3. True or false: a counting loop is a good example of an indefinite loop.

6.1.2: Indefinite Loop Example

  • As an example of an indefinite loop, let us look at the problem of compounding interest
  • If we invest $10,000 at 5% interest, compounded annually, our savings grow like this:
    Year Balance
    0 $10,000
    1 $10,500
    2 $11,025
    3 $11,576.25
    4 $12,155.06
    5 $12,762.82
  • How many years does it take for the initial investment to double?
  • To solve this problem we use a while loop:
    double balance = 10000;
    int year = 0;
    while (balance < 20000) {
        year++;
        double interest = balance * 0.05; // 5% interest
        balance = balance + interest;
    }
    
  • We can make the loop work for any interest rate, starting balance and target amount as shown below

Program with an Indefinite Loop

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
30
31
32
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    double balance = 0;
    double target = 0;
    double rate = 0;

    cout << "Enter the starting balance: ";
    cin >> balance;
    cout << "Enter the interest rate as a percent: ";
    cin >> rate;
    cout << "Enter the target amount: ";
    cin >> target;

    cout << fixed << setprecision(2);
    cout << "\nYear\tBalance\n";

    int year = 0;
    cout << year << '\t' << balance << endl;
    while (balance < target) {
        year++;
        double interest = balance * rate / 100;
        balance = balance + interest;
        cout << year << '\t' << balance << endl;
    }
    cout << "\nTarget amount of $" << target
         << " reached after " << year << " years.\n" ;

    return 0;
}

6.1.3: Processing a Sequence of Inputs

  • Another common use for indefinite loops is to process a sequence of inputs
  • As an example, let us add up (sum) a series of numbers
  • Every number is added to the sum
  • We use a loop to repeat the input until the user decides to stop
  • Since we do not know how many number the user will enter, we use an indefinite loop as shown below
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

int main() {
    double input = 1;
    double sum = 0;
    char repeat = 'y';

    cout << "I will add up numbers for you\n\n";
    while ('y' == repeat) {
        cout << "So far, sum = " << sum << endl;
        cout << "Enter a number: ";
        cin >> input;
        sum = sum + input;

        cout << "Another number? (y/n) ";
        cin >> repeat;
    }
    cout << "Ending sum: " << sum << endl;

    return 0;
}

Terminating the Input with a Sentinel

A sentry

  • Whenever we read a sequence of input values, we need to have some way of terminating the input loop
  • We could use a separate variable and input statement as we have done before:
    char repeat = 'y';
    while ('y' == repeat) {
        // ... statements to repeat
        cin >> repeat;
    }
    
  • However, when entering numbers (or other data) repeatedly, answering an extra question each time through the loop becomes annoying
  • One way to avoid asking an extra question is to use a sentinel value
  • A sentinel is guard who watches for something to happen
  • Similarly, a sentinel in a program watches for a specific sentinel value that signals termination of a loop
  • To use a sentinel value, we must have a special value in the input
  • Some commonly used sentinel values for numeric input are 0 or -1
  • However, if our application suggests another value, then we should use that value
  • In pseudo-code, a sentinel loop generally looks like this:
    read the first value
    while value is not the sentinel
        process the value
        read the next value
    
  • The following program is an update of the previous program to use a sentinel value to end the loop

Example Application Using a Sentinel Value for the Loop Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

int main() {
    double input = 1;
    double sum = 0;

    cout << "I will add up numbers for you\n\n";
    cout << "Enter a number or 0 to exit: ";
    cin >> input;
    while (input != 0) {
        sum = sum + input;
        cout << "So far, sum = " << sum << endl;
        cout << "Enter a number or 0 to exit: ";
        cin >> input;
    }
    cout << "Ending sum: " << sum << endl;

    return 0;
}

Check Yourself

  1. A special value a program looks for in the input stream to know when to end user input is called a(n) ________ value.
  2. In the example application, if a user enters a 0 as their first input the loop ________.
  3. True or false: it is always possible to have a sentinel value. If you think it is not possible, give an example.

6.1.4: Maximum and Minimum Values

  • Sometimes we need to find the maximum or minimum number of a group
  • For instance we may want to know the highest score on a test
  • We use a loop to ask the user for a new value repeatedly
  • As we get each new score, we test to see if it is larger than the previous maximum
    if (score > max) {
        max = score;
    }
    
  • We further explore the algorithm in the following activity

Diagram of Finding a Maximum Value

Finding a maximum value
source

Activity: Maximum and Minimum Values

  1. Students line up and each student chooses a number between one and 100.
  2. Start at one end of the line and each student passes the maximum-value-so-far to the next student in line.
  3. Repeat for the minimum value.

Developing an Algorithm for Maximum Value

  1. Write down the algorithm for finding the maximum value in psuedocode. (3m)
  2. Students review their algorithm with another student. (1m)

Activity Check

  1. The initial minimum or maximum value in a series is the ________ value.
  2. To compare if the next value is smaller or larger than the current value, we use an ________ statement.
  3. Unless we know the number of values in advance, we collect the input with a(n) ________ loop.
    1. for
    2. while
    3. counting
    4. indefinite

Example of Finding a Maximum Value

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
#include <iostream>
using namespace std;

int main() {
    double max = 0, value = 0;

    cout << "Enter positive numbers (0 or less to exit): ";
    cin >> value;
    max = value;

    while (value > 0) {
        if (value > max) {
            max = value;
        }
        cout << "Highest value so far: " << max << endl;
        cout << "Enter the next positive value (0 or less to exit): ";
        cin >> value;
    }
    if (max > 0) {
        cout << "Highest value: " << max << endl;
    } else {
        cout << "No data!\n";
    }
    return 0;
}

6.1.5: Input Validation

  • Another common use for indefinite loops is input validation
  • Input validation combines a loop with one or more if statements
  • The input statement is placed inside the loop
  • The if-statement tests for an incorrect input value
  • The loop repeats while the user's input contains an error
  • Since we do not know how many times the loop must execute ahead of time, the loop is indefinite
  • For example, the following program uses a loop to ensure a user enters a positive number
  • The if statement is used to decide when to output an error message

Example of Input Validation Using a Loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

int main() {
    double input = 0.0; // initialize value
    while (input <= 0) {
        cout << "Enter a positive number: ";
        cin >> input;
        if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    }
    cout << "You entered: " << input << endl;

    return 0;
}

Check Yourself

  1. True or false: in the above code, the variable input must be initialized to a number less that or equal to zero to enter the loop.
  2. True or false: input validation, like the above code, contains an indefinite loop.
  3. True or false: many input validation loops, like the above, have two tests for the error condition.
  4. The purpose of an if-statement when validating input is to ________.
    1. initialize the input variable
    2. display a message on error
    3. loop when an error is found
    4. print the value entered
  5. The purpose of an while-statement in the above example is to ________.
    1. initialize the input variable
    2. check for errors
    3. loop when an error is found
    4. print the value entered

6.1.6: do-while Statements

  • Sometimes we want to execute the body of a loop at least once and perform the loop test after the body was executed
  • For this we can use the do-while (or just do) loop:
    do {
       statements
    } while (test); // loop test
    
  • Where:
    • statements: the statements to execute the first time and repeatedly while the test remains true
    • test: the test condition to evaluate
  • The loop test is placed after the body and executes at the end of the loop
  • The statements in the body of the loop always execute at least once
  • One common use of a do-while loop is to validate user input
  • The following code shows an example where we force the user to enter a positive value

Example do-while Loop Used to Validate Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

int main() {
    double input = 0.0; // initialize value
    do {
        cout << "Enter a positive number: ";
        cin >> input;
        if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    } while (input <= 0.0); // test condition at end
    cout << "You entered: " << input << endl;

    return 0;
}

When to Use do-while Statements

  • Use the do-while loop to force a minimum of one iteration
  • Note that we can accomplish the same control flow with a while loop
  • However, in some cases we can save a statement by using a do-while loop

Check Yourself

  1. True or false: in the above code, the variable input must be initialized to a number less that or equal to zero to enter the loop.
  2. True or false: the test of a do-while loop occurs at the end of the loop.
  3. True or false: the body of a do-while loop always executes at least one time.
  4. The reason to use a do-while loop, instead of a while loop, is to ________.
  5. After reading this comic, explain the potential problem with do-while.

6.1.7: Checking for cin Failure

  • Another problem arises if the user enters a string when we expect a number
  • For instance, in the following, we get incorrect results if the user enters "seven"
    double input = 0.0;
    cin >> input;
    
  • The problem is that cin cannot convert the word "seven" into the number 7
  • When this happens cin fails, sets an error flag and skips the rest of the input operation
  • We can detect the failure condition using code like:
    if (cin.fail()) {
        cout << "The stream failed\n";
    }
    
  • The opposite of cin.fail() is cin.good()
    if (cin.good()) {
        cout << "The stream is good\n";
    }
    
  • Another way to test for cin failure is:
    cin >> input;
    if (cin) {
        cout << "The stream is good\n";
    } else {
        cout << "The stream failed\n";
    }
    
  • Using cin by itself is the same as using cin.good()
  • Yet another commonly used strategy is:
    if (cin >> input) {
        cout << "The stream is good\n";
    } else {
        cout << "The stream failed\n";
    }
    
  • If cin >> input fails to read a correct type of data then cin fails and returns false
  • To clear the failed state we must clear both the error state and the input stream like:
    cin.clear(); // clear error state
    cin.ignore(1000, '\n'); // clear input buffer
    
  • Using cin.clear() will clear the error state but leaves the bad input in the input stream
  • Adding cin.ignore(1000, '\n'); will clear all the input a user enters until the user presses an enter key
  • The 1000 is just a large number

Example Program with Input Validation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int main() {
    double input = 0.0;
    do {
        cout << "Enter a positive number: ";
        cin >> input;
        if (cin.fail()) {
            cout << "You must enter digits, not words\n";
            cin.clear();
            cin.ignore(1000, '\n');
            input = -1; // set loop test to fail
        } else if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    } while (input <= 0.0);
    cout << "You entered: " << input << endl;

    return 0;
}

Failure as a Sentinel Value

  • We can detect cin failure with a while-loop like we can with if-statements
    while (cin.fail())
    
  • If cin fails from the wrong type of input, we can treat if as a sentinel value for a loop
  • For example, if we have a series of numbers to enter we can exit the loop by entering a letter
    int sum = 0;
    int input = 0;
    cout << "Enter a number or q to quit: ";
    while (cin >> input) {
        // the stream did not fail
        sum += input;
        cout << "Enter a number or q to quit: ";
    }
    // cin has failed
    cout << "Sum: " << sum << endl;
    
  • If we use cin again, we will need to clear the input stream and error state as before
    cin.clear(); // clear error state
    cin.ignore(1000, '\n'); // clear input buffer
    

Check Yourself

  1. True or false: when a user enters the wrong type of data, cin may fail.
  2. To check cin for failure, call the cin function named ________.
  3. To clear a cin failure call the ________ function.
  4. Of the following, ________ will clear the input buffer.
    1. cin.clear();
    2. cin.clearBuffer();
    3. cin.ignore(1000, '\n');
    4. cin.ignore(1000 or '\n');

More Information on Selected cin Functions

Exercise 6.1: Processing User Input (10m)

In this exercise we use indefinite loops to process user input and to ensure correct user input.

Specifications

  1. Copy the following program into a text editor, save it as scores.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    #include <climits>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    
  2. Declare two variables of type double named sumScores and nextScore and initialize the variables to 0. In addition, declare an integer variable named count and initialize it to 0. The following is the psuedocode for these steps:
    set sumScores to 0
    set nextScore to 0
    set count to 0
    

    Compile your code to make sure you declared the variables correctly.

  3. Now we want to use a loop to enter a series of scores. Since we do not know how many scores to enter, we use an indefinite loop like the following:

    Listing of while loop

    In addition, add a statement to display sumScores after the loop.

    Compile your code to make sure you added the loop correctly. To exit the loop you will need to enter a negative number.

  4. The loop includes statements to collect the sum of the scores in the variable named sumScores. Add a statement after the loop to print sumScores to the console. When you run the program after adding this code, the output should look like:
    Score 1: 38
    Score 2: 39
    Score 3: -1
    
    Sum of scores: 77
    

    The loop uses the sumScores variable to accumulate scores during each repetition of the loop like that shown in lesson: 6.1.3: Processing a Sequence of Inputs.

  5. We could write our indefinite loop using a do-while loop instead. Replace your current loop with the following:

    Listing of do-while loop

    Note that the statements inside the loop did not change, only the loop statement itself. To make sure you made the changes correctly, compile and run your code and check to see if it works the same. The difference between a while and do-while loop is that a do-while ensures the body of the loop is executed at least once. For more information see lesson: 6.1.6: do-while Statements.

  6. One problem with our program is the user can still enter letters instead of digits. We can prevent this error by checking cin.fail() and looping until the user enters a correct value. Replace the current if statement with the following:

    Error checking if statement

    Note that the second if statement is the same as the current if statement. Compile and run your program to make sure you added the changes correctly. Try entering letters instead of digits and verify you see an error message. For more information see section: 6.1.7: Checking for cin Failure.

  7. Save your final program source code to submit to Canvas as part of assignment 6.

When finished, please help those around you.

6.1.8: Summary

  • In this section we looked at using indefinite loops
  • With an indefinite loop, we do not know how many time the loop will execute ahead of time
  • One example was the main loop, where we let the user repeat a program
  • Since we do not know how many times the user will repeat ahead of time, the loop is indefinite
  • Another indefinite loop example was how long it took an investment to double
  • The amount of time depends on the investment and the interest rate
  • Another common use for indefinite loops is to process a sequence of inputs
  • Whenever we read a sequence of input values, we need to have some way of terminating the input loop
  • Since entering extra data each time through a loop is annoying, we discussed using a sentinel value to terminate the loop
  • A sentinel controlled loop looks for a sentinel value in the input data
  • A sentinel value is a special number (or other data) used to signal termination of a loop
  • We looked at how to sum numbers with a sentinel-controlled loop
  • Another common use for indefinite loops is input validation
  • Input validation combines a loop with one or more if statements
  • The loop repeats input until the user enters reasonable input
  • Since we do not know how many times the loop must execute ahead of time, the loop is indefinite
  • Another looping statement is the do-while loop, which tests the condition at the end of the loop body:
    do {
       statements
    } while (test); //loop condition
    
  • Testing at the end ensures a minimum of at least one iteration
  • We also looked at how to test cin for failure
  • The cin input stream fails if the user enters a string when we expect a number
  • We looked at how to add checks for cin failure to our input validation
  • Finally, we discussed a step-by-step procedure for developing loops

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. What is an indefinite loop? (6.1.1)
  2. How many times does an indefinite loop execute? (6.1.1)
  3. For the program in section 6.1.2, how many years does it take to double $10,000 at 10% interest? (6.1.2)
  4. What is a sentinel value? (6.1.3)
  5. What is the advantage of using a sentinel value to terminate a loop? (6.1.3)
  6. What statements do we need to find a minimum or maximum value in a series of input? (6.1.4)
  7. What is input validation? (6.1.5)
  8. What is the difference between a while and a do-while loop? (6.1.6)
  9. What is a test condition you can use to see if cin has failed? (6.1.7)
  10. What is a good test to validate that the user did not enter a string after the following statements execute: (6.1.7)
    double x;
    cout << "Enter a number: ";
    cin >> x;
    
  11. What two statements can you use to fix cin if it has failed due to bad input? (6.1.7)

6.2: More About Strings and Characters

Learner Outcomes

At the end of the lesson the student will be able to:

  • Iterate through a string and extract each character
  • Convert characters to digits
  • Use string functions

6.2.1: Strings Versus Characters

  • Remember that a string is a series of characters enclosed in double quotes such as:
    "Hello"  "b"  "3.14159"  "$3.95"  "My name is Ed"
  • We can store text in a variable of type string, like:
    string firstName;             // declaration
    firstName = "Edward";         // assignment
    string lastName = "Parrish";  // declaration + assignment
    cout << firstName << " " << lastName << endl;
    
  • On the other hand, a character is a single letter, number or special symbol
  • We enclose characters in a single quote, rather than a double quote, like:
    'a'   'b'   'Z'   '3'   'q'   '$'   '*'
  • Also, we store a a single character using a variable of type char, such as:
    char letterA = 'A';
    char letterB = 'B';
    
  • Each character is stored as a number, using its ASCII Table value
  • By declaring a char variable or using single quotes, C++ knows to treat the number as a character
  • Thus, when we print a character, we see a letter rather than a number:
    char letter = 'A';
    cout << letter << 'B' << endl;
    
  • As we can see, a string is made up of characters and characters are numerical codes
  • We can use this information to work with characters and strings

String Concatenation and Functions

  • Recall that we can join (concatenate) two strings or a string with a character
    string str = "abc";
    str = str + "1"; // allowed
    str = str + '1'; // allowed
    str = str + 1;   // NO
    str = str + 1.2; // NO
    
  • However, we cannot concatenate a string with a number
  • Because strings are objects, they have member functions
  • Two useful member functions we have studied are length() and substr()
  • length(): Returns the number of characters in a string
    string str = "Hello";
    cout << "The number of characters is " << str.length()
         << ".\n";
    
  • substr(i, n): Returns a substring of length n starting at index i
    string greeting = "Hello, World!\n";
    string sub = greeting.substr(0, 4);
    cout << sub << endl;
    
  • The position numbers in a string start at 0. The last character is always one less than the length of the string
    H e l l o , W o r l d !
    0 1 2 3 4 5 6 7 8 9 10 11 12
  • string w = greeting.substr(7, 5);
    H e l l o , W o r l d !
    0 1 2 3 4 5 6 7 8 9 10 11 12

Check Yourself

  1. True or false: strings are a sequence of characters.
  2. True or false: "A" and 'A' are the same.
  3. The following code is wrong because ________.
    cout << "3.14159" * 2;
    
    1. you cannot double PI
    2. 3.14159 is not exact enough to represent PI
    3. string may be added but not multiplied
    4. "3.14159" is not a number
  4. After the following code executes, it displays ________.
    char ch;
    ch = 'd' - 'a' + 'A';
    cout << ch << endl;
    
    1. 'D'
    2. D
    3. 68
    4. d

6.2.2: Indexing a String

  • Strings are stored in a character sequence starting at 0 (zero)

    String character positions

  • We can access any individual character of a string variable using square brackets [ ]
  • The general syntax is:
    stringVariable[index];
    
  • Where:
    • stringVariable: the name of your string variable
    • index: the number of the character position
  • For example:
    string str = "abcdef";
    char firstLetter = str[0];
    cout << firstLetter << str[1] << endl;
    
  • The above code displays:
    ab
  • Notice that the square bracket notation returns a char data type

Check Yourself

For the following string declaration, answer the questions below:

string str = "C++ Rules!";
  1. The value of str[0] is: ________
  2. The value of str[2] is: ________
  3. The value of str[4] is: ________
  4. The value of str[str.length() - 1] is: ________

6.2.3: Iterating Strings

  • Recall that member function length() returns the number of characters in a string variable:
    string s = "abcdef";
    unsigned n = s.length();
    
  • Since a string's length is always 0 or a positive number, the length() function returns an unsigned int type
  • After we know the length, it is easy to iterate through the individual characters of a string using a counting loop:
    cout << "Enter a word: ";
    string msg;
    cin >> msg;
    for (unsigned i = 0; i < msg.length(); i++) {
        cout << "Char[" << i << "]: " << msg[i] << endl;
    }
    

Using unsigned

  • Note the use of unsigned i in the for loop
  • Specifying unsigned assumes int by default
  • So rather than unsigned int we may just code unsigned as the data type
  • Recall from lesson 3.1.3 that unsigned ranges from 0 to 4294967295 rather than -2147483647 to 2147483647 for int
  • The length() function returns an unsigned number because the length of a string is never less than zero
  • If you compare a signed number with an unsigned number, the compiler may issue a warning:

    warning: comparison between signed and unsigned integer expressions

  • By using unsigned as the counting variable type in the for loop you avoid the warning

Try It: iterating Strings (4m)

  1. Copy the following program into a text editor, save it as test.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    
  2. Add the code to prompt for and read a messages from the user:
    cout << "Enter a word: ";
    string msg;
    cin >> msg;
    
  3. Next add the following for-loop code to the main() function.
    for (unsigned int i = 0; i < msg.length(); i++) {
        cout << i << ": " << msg[i] << endl;
    }
    
  4. Compile and run your code. What do you see when you compile?
  5. Be prepared to answer the following Check Yourself questions when called upon.

Check Yourself

  1. True or false: the length() function of a string returns an unsigned integer.
  2. For the following code, the output the second time through the loop is ________
    string msg = "aeiou";
    for (unsigned i = 0; i < msg.length(); i++) {
        cout << "Char[" << i << "]: " << msg[i] << endl;
    }
  3. True or false: the compiler may give a warning if you compare an unsigned int with a signed int.
  4. Each character in the above loop is printed on it own line because of the ________.

6.2.4: String Input With Spaces

  • We have been using the >> operator to enter data into a string variable:
    string something;
    cout << "Enter something: ";
    cin >> something;
    cout << "You entered: " << something << "END OF OUTPUT\n";
    
  • However, there are some complications
  • >> skips whitespace and stops on encountering more whitespace
  • Thus, we only get a single word for each input variable
  • If a user types in "Hello Mom!", we would only read "Hello" and not " Mom!"
  • This is because cin >> s1 works as follows:
    1. Skips whitespace
    2. Reads non-whitespace characters into the variable
    3. Stops reading when whitespace is found

Input Using getline()

  • To read an entire line we use function getline()
  • Syntax:
    getline(cin, stringVariable);
    
  • Where:
    • stringVariable: the name of the string variable
  • For example:
    string line;
    cout << "Enter a line of input:\n";
    getline(cin, line);
    cout << line << "END OF OUTPUT\n";
    
  • Note that getline() stops reading when it encounters a '\n'

The Problem with Newlines

  • When you press the Enter key, a newline character ('\n') is inserted as part of the input
  • The newline character can cause problems when you mix cin >> with getline()
  • Recall that cin >> s1:
    1. Skips whitespace
    2. Reads non-whitespace characters into the variable
    3. Stops reading when whitespace is found
  • Since whitespace includes newline characters, using cin >> will leave a newline character in the input stream
  • However, getline() just stops reading when it first finds a newline character
  • This can lead to mysterious results in code like the following:
    cout << "Enter your age: ";
    int age;
    cin >> age;
    cout << "Enter your full name: ";
    string name;
    getline(cin, name);
    cout << "Your age: " << age << endl
         << "Your full name: " << name << endl;
    
  • To correct this problem we use cin >> ws just before getline()
    cin >> ws; // clear whitespace from input stream
    
  • We can see how to use this fix in the following example

Example Using cin >> ws

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

int main() {
    cout << "Enter your age: ";
    int age;
    cin >> age;
    cout << "Enter your full name: ";
    string name;
    cin >> ws; // clear whitespace from buffer
    getline(cin, name);
    cout << "Your age: " << age << endl
         << "Your full name: " << name << endl;
}

Check Yourself

  1. True or false: Using the >> operator with string variables only reads one word at a time.
  2. To read strings containing multiple words use the ________ function.
  3. True or false: before you switch from using the >> operator to using getline(), you must clear the next newline character from the input buffer.
  4. To clear whitespace from the input buffer use: ________.

6.2.5: Processing Text Input

  • Sometimes we need to read input as words and sometimes as lines
  • To input a sequence of words, use the loop:
    string word;
    while (cin >> word) {
       // process word
       cout << word << endl;
    }
    
  • cin >> word is the same test as cin.good() (see lesson 6.1.7)
  • To process input one line at a time, use the getline() function
    string line;
    while (getline(cin, line)) {
       // process line
       cout << line << endl;
    }
    
  • getline(cin, line) returns true as long as there is input remaining
  • The following example processes text input by counting words
  • When reading input in the while test, you need to close the stream using:
    • Ctrl + Z in Windows
    • Ctrl + D in Linux or OS X
  • Closing the stream acts as a sentinel value for the loop
  • When the stream fails the loop exits

Example Program that Reverses a Sentence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>

using namespace std;

int main() {
    cout << "Enter a phrase followed by the Enter"
         << " key and Ctrl-Z/D.\n";
    string word;
    int count = 0;
    while (cin >> word) {
        count++;
    }
    cout << "Number of words: " << count << endl;

    return 0;
}

Redirection of Input and Output

  • We could use the above program by typing words at the command line
  • However, that quickly gets tedious
  • A better way is to use redirection of input (see textbook page 154)
  • The command line interfaces of most operating systems have a way to link a file to the input of a program
  • The content of the file gets fed into the program as if all the characters had been typed by a user
  • For example, after compiling the above program we type something like the following at the command line:
    ./words < input.txt
    
  • Where input.txt is the text file on which we want to count words
  • You can redirect program output to a file as well using something like:
    ./words > output.txt
    
  • You can combine input and output redirection in one command:
    ./words < input.txt > output.txt
    

Check Yourself

  1. True or false: the following code reads input one word at a time.
    string str;
    while (cin >> str) {
       cout << str << endl;
    }
    
  2. True or false: the following code reads input one line at a time.
    string str;
    while (getline(cin, str)) {
       cout << str << endl;
    }
    
  3. To close the cin input stream use the Ctrl key plus the ________ key.
  4. True or false: most operating systems let you redirect input and output at the command line.

Exercise 6.2: Finding Words (5m)

In this exercise we write code to find words in a text file. Compile and test after each step to verify your work.

Specifications

  1. Copy the following program into a text editor, save it to the home folder of Cygwin or your Terminal window as findword.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    
  2. Inside main(), declare both a string variable named word and an integer variable named count, like:
    string word;
    int count = 0;
    
  3. Add a while loop to read one word at a time from cin, like:
    while (cin >> word) {
        // Add if statements here
    }
    
  4. Inside the while loop write code to add one to the count variable.
  5. Add two if-statements, one to test for the word "Shazam" and one to test for the word "bogus", reporting the word count where the word was found. For example:
    if (word == "Shazam") {
        cout << "Shazam is word " << count << endl;
    }
    
  6. Test your program by saving the words.txt file into the home folder of Cygwin or your Terminal window.

    words.txt

  7. Run the program from the command line using input redirection:
    ./findword < words.txt
    
  8. Save your program source code to submit to Canvas as part of assignment 6.

Finding Words

Code to process strings in a loop

As time permits, read the following sections and be prepared to answer the Check Yourself questions in the section: 6.2.6: Summary.

6.2.6: Summary

  • A string is a series of characters enclosed in double quotes
  • We can store text in a variable of type string, like:
    string s1 = "Hello Mom!";
  • A character is a single letter, number or special symbol
  • We can store a a single character using a variable of type char, such as:
    char letterA = 'A';
    char letterB = 'B';
    
  • Each character is stored as a number, using its ASCII code
  • Strings are stored in a character sequence starting at 0 (zero)

    String character position

  • We can access individual characters of a string using []
  • Strings are a special type of variable called objects, just like a Turtle
  • Because a string is an object, it has member functions
  • We can iterate through a string using a loop and the length() member function:
    string s = "abcdef";
    for (unsigned i = 0; i < s.length(); i++) {
        cout << "Char[" << i << "]: " << s[i] << endl;
    }
    
  • To read an entire line, you need to use the getline() function:
    getline(cin, line);
  • Sometimes cin >> can leave a '\n' character in the input stream
  • To get around this problem you can use cin >> ws before getline()
    cin >> ws; // clear whitespace from buffer
    

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. String are enclosed in double quotes. What type of quote marks enclose characters? (6.2.1)
  2. The characters of a string variable can be accessed using what brackets? (6.2.2)
  3. The leftmost character of a string is accessed using which index number? (6.2.2)
  4. To print the following string vertically down the page, what code do you write? (6.2.3)
    string str = "Hi mom!";
  5. To convert the following char variable to a number, what code do you write? (6.2.4)
    char ch = '7';
  6. What is the value of the expression: 'd' - 'a' + 'A'? (6.2.4)
  7. To convert the following string variable to a number, what code do you write? (6.2.4)
    string str = "7";
  8. How many words can you enter with the following code? (6.2.5)
    string something;
    cout << "Enter something: ";
    cin >> something;
    cout << "You entered: " << something << endl;
    
  9. How can you change the previous code to read a string that includes spaces? (6.2.5)
  10. What code can you use to clear newlines and other whitespace from the input stream? (6.2.5)

Wrap Up

Due Next:
A5-Midterm 1 Preparation (10/5/17)
A6-Loopy Programs (10/12/17)
  • When class is over, please shut down your computer
  • You may complete unfinished exercises at the end of the class or at any time before the next class.
Last Updated: October 08 2017 @15:57:54