Welcome to Lesson 21!

Learning Objectives

By the end of today's class, you should know...
  • How do you use loops to read in input from a file and write output to a file?
  • How do you store a collection of data under a common name in C++?
  • How do you declare an array and assign it values - in 2 ways?
  • How is data stored in an array?
  • How can you use a for loop to print the data in an array?

Announcements

  • Final Exam one week from today
    • No makeups - the exam must be taken on the day and at the time given
    • How to study: Old Quizzes, Midterms, Programs (In and Out of Class)
    • Final will be cumulative from first day of class through Thursday's (short) lesson
    • Will provide practice for the final on Thursday
  • Last lab due Friday at midnight
    • Arrays
  • Last day to submit any late assignments (no more than one week late) or revisions is this Thursday's office hour
    • Gradebook closes at 1:20pm on Thursday
    • This includes tonight's assignment
    • My advice: Don't come to this office hour if you can come to an earlier one
    • If you must come on Thursday, come early
    • This office hour will be packed!
    • Will only be able to help 6-8 people



Review Activity

1. What will be the value of the num variable after calling the following functions:


void doubleVal(int& value){
    value *= 2;
}

void tripleVal(int value) {
    value *= 3;
}

int main() {
    int num = 3;
    doubleVal(num);
    tripleVal(num);
    cout << num;
}
2. Assume you have a text file named words.txt containing the words: cat, bat, rat, write 9 lines of code to do the following:
  • Declare an input file stream variable named fin.
  • Use fin to open up the words.txt file for reading
  • Use an if statement to check for failure.
    • If the file does not open, print a message to the console stating "Words.txt did not open."
    • Then, exit the program
  • Read in the first word in the file, and save it in a string variable called word1.
  • Print the contents of word1 to the console
  • Close fin.


Using Loops to Read Files

  • Sometimes we do not know how many data items are in a file
  • To solve this problem, the typical approach is to use a loop to process the file
  • When reading input from the console, we can read the input as part of the test condition like:
    while (fin >> nextNum) { //returns true or false AND reads in the number!
        // process the input
    }
    
  • We saw this technique when we were checking cin for failure
  • While the read is successful, the input stream returns a value interpreted as true
  • If the stream fails or closes, then the test condition fails
  • This failing condition returns a value interpreted as false by the loop
  • Thus the loop ends and the program continues after the loop statement
  • We can use this behavior to read from a file as shown below

Example Program Reading a File Using a Loop


#include <fstream>   // for file I/O
#include <iostream>
#include <cstdlib>
using namespace std;

int main() {
    ifstream fin;
    fin.open("infile.txt");
    if (fin.fail()) {
        cout << "Input file failed to open.\n";
        exit(-1);
    }

    double nextNum, sum = 0;
    int count = 0;
    while (fin >> nextNum) {
        cout << "Read: " << nextNum << endl;
        sum = sum + nextNum;
        count++;
    }
    cout << "average = " << (sum / count) << endl;
    fin.close();

    return 0;
}



Activity 21.1: Averages (10pts)

  • We are going to write a program that takes in a list of numbers of unknown size from a file, and then outputs the average of these numbers.
  • This activity will help you practice using a loop to help you read data from a file.
  • Open up a new C++ file in Eclipse and name it averages.cpp
  • Copy and paste the starter code below into your file.
#include <iostream>
using namespace std;

int main() {
    
    return 0;
}
  • Now add the two additional libraries that are required for file I/O to the top of your program:
#include <fstream>
#include <cstdlib>
  • Next, lets create a new input stream variable at the top of main
ifstream fin;
  • Then, let's use this stream to open a file called numbers.txt
fin.open("numbers.txt");
  • Next, we will need to make sure that the file opened successfully by checking for failure:
if (fin.fail()) {
        cout << "Input file failed to open.\n";
        exit(-1);
}

  • Next, lets read in the numbers from the file. Since we are computing the average of the numbers, we need two pieces of information
1. The sum of the numbers
2. How many numbers there are
  • Remember: Average = sum / count
  • Therefore, as we read in the numbers from the file, we need to computer their sum and count how many there are.
  • We will therefore need two variables to keep track of this information. Add the following two variable declarations to the top of main:
double sum = 0.0;
int count = 0;
  • We will also need a variable to temporarily store each number as we read it in from the file. Add an additional variable declaration to the top of main like so:
double num;
  • Now, let's read in the numbers from the file and process them inside a loop. Add the following loop to your program:
while (fin >> num) {
    cout << "Processing the number: " << num << endl;
    sum += num; //adding the number to our running total for the sum
    count++; //counting how many numbers are in the file
}
  • Now, let's print the average to the console and output it to a file.
  • To print the average to the console, add the following line of code:
cout << "The average is: " << sum/count << endl;
  • To output the average to a file, we need to open a new output stream. Below the cout statement, add the following line of code:
ofstream fout;
  • Then, we need to open a file to write out to it. Let's open a file named average.txt.
fout.open("average.txt");

  • Before we can proceed, we need to make sure the file opened properly:
if (fout.fail()) {
    cout << "Output file failed to open." << endl;
    exit(-1);
}

  • Finally, lets write the average to the file.
fout  << "The average is: " << sum/count << endl;
  • As a last step we need to close our input and output streams. Add the following lines of code to the bottom of main:
fin.close();
fout.close();
  • Let's create a file to test our program. Create a new text file in Eclipse called numbers.txt with the following contents:
10
20
30
40
50
  • Save the file in the same directory in which you are executing your source code files and close it.
  • Now, run the code and open up your file to make sure everything is working properly. Open up the file averages.txt and verify that you got the correct output.
  • When you are finished, upload averages.cpp to Canvas.

}

Reading Files using getline()

  • Recall that you can read text using a loop and an input stream like fin:
    int count = 0;
    string word;
    while (fin >> word) {
        count++;
    }
    cout << count << " words.\n";
    
  • However, just like with cin, there are complications when you want to read words with spaces between them
  • >> skips whitespace and stops on encountering more whitespace
  • Thus, you only get a single word for each input variable
  • If you want to read a complete line of text like "Hello Mom!", you need to use getline()
  • For example:
    ifstream fin;
    // ... more code here
    string line;
    getline(fin, line);
    cout << "Read data: " << line << endl;
    
  • Recall that getline() stops reading when it encounters a '\n'
  • By contrast, fin >> variable operates as follows:
    1. Skips whitespace
    2. Reads characters
    3. Stops reading when whitespace is found
  • Thus if you mix fin >> variable followed by getline(fin, line), you get mysterious results
  • Just like with cin, you get around this problem you by either:
    1. Only use getline() before using fin (and never after using fin)
    2. Use fin >> ws; before using getline()

Using Loops with getline()

  • Sometimes you need to read and process an unknown number of lines in a file
  • For this you can use the getline() function in a loop as well:
    while (getline(fin, line)) {
        // process input
    }
    
  • While the read is successful, the getline() function returns a value interpreted as true
  • If the stream fails or closes, then the test condition fails
  • You can see an example of using getline() to read lines from a file in the following program

Example Program Reading a File Using getline() in a Loop


#include <fstream>   // for file I/O
#include <iostream>
#include <cstdlib>
using namespace std;

int main() {
    ifstream fin;
    fin.open("infile.txt");
    if (fin.fail()) {
        cout << "Input file failed to open.\n";
        exit(-1);
    }

    string line;
    int count = 1;
    while(getline(fin, line)) {
        cout << "Line " << count << ": "
             << line << endl;
        count++;
    }

    fin.close();

    return 0;
}


Activity 21.2: Sonnet Statistics (10 pts)

  • Open up a new C++ file named statistics.cpp and add the starter code below to it:

#include <iostream>

//Add library for file I/O

//Add library for exit()

using namespace std;

int main()

{

    int count = 0;

    string word, line;

    return 0;

}

  • Now, create a new text file in Eclipse called sonnet.txt and copy and paste the below sonnet into your file:

Shall I compare thee to a summer’s day?
Thou art more lovely and more temperate:
Rough winds do shake the darling buds of May,
And summer’s lease hath all too short a date;
Sometime too hot the eye of heaven shines,
And often is his gold complexion dimm'd;
And every fair from fair sometime declines,
By chance or nature’s changing course untrimm'd;
But thy eternal summer shall not fade,
Nor lose possession of that fair thou ow’st;
Nor shall death brag thou wander’st in his shade,
When in eternal lines to time thou grow’st:
So long as men can breathe or eyes can see,
So long lives this, and this gives life to thee.

  • We are going to write some code to count the number of words and the number of lines in this file.
  • First, declare a new input stream variable named fin.

ifstream fin;

  • Next, open up sonnet.txt for reading.

fin.open("sonnet.txt");

  • Don't forget to check for failure!

if(fin.fail())
{
    cout << "Input file failed to open!" << endl;
    exit(-1);
}
  • Note that I have provided you with the code above, but you will need to know it from your own memory for the final!
  • You can practice by remembering the code for the output stream.
  • Beneath your if statement to check for input file failure, create a new output stream variable named fout.
  • Then, open up a new text file named statistics.txt for writing.
  • Don't forget to check for failure!
  • Now, let's write a while loop to count up how many words are in the file.
  • Will you need getline(fin, line) or will you need fin >> word?
while (?????) {
    count++;
}
  • Finally, write an fout statement to print the number of words contained in the file:
fout << "The sonnet has " << count << " words\n";
  • Now, close your input file stream.
fin.close();

  • Now, we need to count the number of lines in the file.
  • For this purpose, we are going to need a new input file stream as we already used the previous one to count the number of words in the file (and we cannot reset the input stream to point to the beginning of the file).
  • Add the following code to your program below the statement to close fin:
ifstream fin2;
fin2.open("sonnet.txt");
//add code to check for failure here
  • Next, we are going to write a while loop to count the number of lines in the file.
  • Do we need getline(fin2, line) or fin2 >> line as the test condition of our while loop?

count = 0; //reset count variable to 0
while (?????) {
    count++;
}
  • Write an fout statement to print out the number of lines in the sonnet.
The sonnet has 14 lines.
  • Finally, close fin2 and fout and run your program.
  • Note that the sonnet has 114 words and 14 lines.
  • Did you get the expected result inside of statistics.txt?
  • Submit your code to Canvas when you are finished.


Introduction to Arrays


Using Lists for Data

  • Often times we need to process a group of the same types of data
  • For instance:
    • Bank account transactions
    • Salaries for employees in a company
    • Test scores for a group of students
    • Temperature data over some period of time
  • Consider how we might process the following student test scores:
    90
    95
    87
    89
    98
    96
    85
    79
    95
    100
  • With this data, we can calculate statistics like:
    • Highest score
    • Lowest score
    • Average (mean) score
    • Difference (deviation) of each score from the average
  • We can write a program to read this data and make the calculations
  • However, to calculate the difference from the mean, we need to first find the mean
  • Thus, we have to process all the data twice: one to find the mean and another to calculate the difference of each score from the mean

Storing Lists of Data

  • If we know there are 10 inputs, we can use 10 separate variables.
int score1 = 90;
int score2 = 95;
int score3 = 87;
int score4 = 89;
int score5 = 98;
int score6 = 96;
int score7 = 85;
int score8 = 79;
int score9 = 95;
int score10 = 100;
  • However, declaring all of these variables and assigning them values is a very tedious process.
  • Now, imagine there were 100 test scores... Or, an unknown number of test scores...
  • We need another system!
  • Fortunately, C++ has techniques we can use to organize lists of data

Defining Arrays

  • An array is a collection of data items all of the same type
  • You declare an array like this:
    dataType variableName[size];
    
  • Where:
    • dataType: the data type of all the array items
    • variableName: the name you make up for the array
    • size: the number of data items the array can hold
  • For example, the following is the declaration of an array named scores that holds 10 values of type int:
    int scores[10]
  • Arrays like this can never change size and the array size must be set when the program is compiled
  • When defining an array, you must guess the maximum number of elements you need to store:
    const int MAX_SCORES = 10;
    int scores[MAX_SCORES];
    
  • The programmer must keep track of the capacity
  • We use a constant to hold the capacity of the array as shown above
  • This allows us to know the size anywhere in our code
  • If we need to change the size, we change only a single constant and recompile
  • When a program executes this statement, it creates 10 contiguous slots in memory like this:
    scores = 
     
     
     
     
     
     
     
     
     
     
  • Each of the memory slots can hold one data value

Initializing Array Items

  • We specify which slot of an array to access with the [] operator:
    scores[4] = 98;
  • The indexes of arrays are numbered starting at 0
  • We can assign a value to an array element any time after it is declared:
    const int MAX_SCORES = 5;
    int scores[MAX_SCORES];
    scores[0] = 90;
    scores[1] = 95;
    scores[2] = 87;
    scores[3] = 89;
    scores[4] = 98;
    
  • We can also initialize array elements in the declaration statement:
    • Called static initialization
    • We use a comma-separated list inside curly-braces
  • For example:
    int scores[] = { 90, 95, 87, 89, 98 };
    
  • This produces the same array as in the previous example
  • The compiler computes the size automatically by counting the items in the list
  • If we want a larger array with only the first few elements initialized, we can use:
    int scores[MAX_SCORES] = {90, 95, 87};
    
  • Note that if we do not assign a value to an array element, its value is not known.

Accessing Array Items

  • To access the slots in an array, we must specify which slot to use with the [] operator
  • For instance:
    scores[4] = 98;
  • The number inside the brackets is called an index or subscript
  • In C++, the slots of an array are numbered starting at 0, as shown below:
    scores = 
     
     
     
     
    98
     
     
     
     
     
    [0]
    [1]
    [2]
    [3]
    [4]
    [5]
    [6]
    [7]
    [8]
    [9]
  • Thus, assignment to the slot with an index of 4 is put into the fifth slot

Using Slots

  • We declared our example array with a data type of int:
    int scores[10];
  • Because scores is an array containing int values, we can use a slot, such as scores[4], just like any variable of type int:
    scores[4]++;
    cout << scores[4] << endl;
    
  • This includes using a slot as an argument to a function with a parameter of the same type:
    void myFun(int singleScore);
    ...
    myFun(scores[4]);
    

Using Arrays to Collect Data Items

  • Note that the index of an array can be any integer value
  • Thus, we can use an integer variable for the index
  • We can use an integer variable with a loop to read data into the array
  • Also, we can display the contents of an array using a loop
  • The following program shows an example of collecting and displaying data items


Example Program Using Arrays to Collect and Display Data Items


#include <iostream>
using namespace std;

int main() {
    const int MAX_SCORES = 10;
    int scores[MAX_SCORES];

    cout << "Enter " << MAX_SCORES << " scores:\n";
    for (int i = 0; i < MAX_SCORES; i++) {
        cin >> scores[i];
    }

    cout << "You entered:\n";
    for (int i = 0; i < MAX_SCORES; i++) {
        cout << scores[i] << endl;
    }

    return 0;
}

Activity 21.3: My First Array (10pts)

  • Open a new HelloWorld program in Eclipse, save it as myarrays.cpp, and then compile and run the starter program.
  • Inside main(), add a statement to define an array named names that is suitable for holding a list of three (3) names.
  • Compile your code to make sure it has correct syntax.
  • Assign values to each of the array elements like:
    names[0] = "Abel Ableson";
    
  • Add a for-loop to display all three array values.
  • Compile your code to make sure it has correct syntax.
  • Then, run it to make sure all three names appear on the console.
  • When you are finished, upload your source code to Canvas.


Upcoming Assignments
  • Assignment 21 due Thursday
  • Lab 11 due Friday at midnight

~ See You Thursday! ~