Welcome to Lesson 20!


Learning Objectives
By the end of today's class, you should know...
  • How do you use loops to read data from a file?
  • How do you pass in an array as a function parameter?

Announcements

  • Final Exam next class!
    • 9:15-11:15am in this classroom!
  • Practice Quiz 8 posted
    • Functions
    • File I/O
    • Arrays
  • Final programs posted - one of these will be selected for the program on your final exam
  • Last lab due Friday at midnight
  • Thursday at 1:30 is my last in-person office hour
    • Last chance to turn in late work
    • No work more than one week late

Review Activity


  • Assuming you have a file named 22aScores.txt which stores student exam scores, write some C++ code to do the following:
    • Declare a new input file stream variable named fin
    • Open the 22aScores.txt file using fin
    • Check for failure
    • Read in the first score into a double variable named score1
    • Close the input file stream
  • Declare an array of doubles named weights and assign it the values 135.6, 150.9, 187.8, 205.9 in TWO WAYS (static and non-static initializaton)!
  • Write a for loop to print out the values in the weights array.

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;
}



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 20.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 nums.txt
fin.open("nums.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. Open up a file nums.txt. In the file, add a list of numbers each on their own line, like this:
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.
}


Activity 20.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, in Eclipse, create a new text file 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.


Arrays as Function Parameters

  • When writing a function with an array parameter, we place an empty [] after the parameter name:
    void print(int values[], int size);
    
  • We pass the size of the array to the function so the function knows the size of the array
    • There is no size() member function for an array
  • When we call the function, we do NOT include the []:
    print(data, size); // function call
    
  • Instead, we pass in the name of the array.
  • Unlike other parameters, you can pass the array into the function and then alter the array inside of the function without needing to return a new array.
  • For example, what do you think will be the result of running the following program?
#include <iostream>
using namespace std;
void fillArray(int data[], int size) {
    for (int i = 0; i < size; i++) {
       data[i] = i;
    }
} 
        int main() {
            const int SIZE = 5;
            int data[SIZE];
            fillArray(data, SIZE);
            for (int i = 0; i < SIZE; i++) {
                cout << data[i] << endl;
            }
        }
  • Note the use of size parameter
  • The programmer must keep track of the size when working with arrays
  • Note that arrays cannot be function return types
  • Returning an array with a return statement is not necessary


Using the const Modifier

  • Normally, a function can change the values of array elements
  • We can prevent the modification using the const modifier:
    void print(const int values[], int size);
    
  • The compiler will issue an error message if you try to change the value of an array element
  • If a function with a constant array parameter calls another function using the const array parameter as an argument, the called function must use a const array parameter as well
  • Otherwise, the compiler will issue an error
  • The following program shows arrays used with functions


Activity 20.3: Exploring Arrays (10 pts)
  • In this exercise we explore declaring, allocating and assigning values to arrays containing lists of data.
  • Create a source code file called myarrays.cpp:
  • Add the following function to the code:
    void print(const int values[], int size) {
        for (int i = 0; i < size; i++) {
            cout << values[i] << " ";
        }
        cout << endl;
    }
    
  • Compile your code to make sure it has correct syntax.

    If you have problems, ask a classmate or the instructor for help as needed.

  • Declare and initialize an array for a list of 10 integer scores after the current arrays using the following code:
    const int NUM_SCORES = 10;
    int scores[NUM_SCORES] = {90, 91, 92, 93, 94, 95, 96, 97, 98, 99};
    
  • After declaring and initializing the array, call the print() function using the code:
    cout << "Integer scores:\n";
    print(scores, NUM_SCORES);
  • Compile and run the program to make sure you made the changes correctly. When you run the program, the output should look like:
    Integer scores:
    90 91 92 93 94 95 96 97 98 99
    
  • Declare and initialize an array of double values holding the the temperature values 25.7, 30.3, and 40.9
  • Write another print() function with two parameters: one for the array of double values and one for the size of the array.
    • Note that you may also name this function print. The compiler will know they are different functions as their parameters are different.
    • This is called function overloading (two functions with the same name, but different parameters in the same program)
  • After declaring and initializing the array, call the print() function.
  • Compile and run the program to make sure you made the changes correctly. When you run the program, the output should look like:
    Integer scores:
    90 91 92 93 94 95 96 97 98 99
    Double temperatures:
    25.7 30.3 40.9
    
  • Declare and allocate an array of char values and assign it the vowels a, e, i, o and u.
  • After declaring and initializing the array, write another print function to display it. Again, this method should be named print(). Then, call this method in main.
  • Compile and run the program to make sure you made the changes correctly. When you run the program, the output should look like this:
    Integer exam scores:
    90 91 92 93 94 95 96 97 98 99
    Double temperatures:
    25.7 30.3 40.9
    Char vowels:
    a e i o u 
  • Finally write a function called addExtraCredit with the following signature:

void addExtraCredit(int scores[], int size){

    //fill in method body here

}

  • This method should add 5 points of extra credit to each value in the scores array.
    • Hint: Add 5 to each array element using a for loop to iterate through all values in the scores array.
  • Write the function and then call it on the scores array like so:

addExtraCredit(scores, NUM_SCORES);

  • Now print out the scores array by calling the print function to verify that the extra credit got added correctly.
  • Your output should now look like the following:
Integer exam scores:
90 91 92 93 94 95 96 97 98 99
Double temperatures
25.7 30.3 40.9
Char vowels:
a e i o u
Exams scores with extra credit
95 96 97 98 99 100 101 102 103 104

  • Submit your program to Canvas when you are finished.


Activity 20.4: Arrays and Functions Worksheet (10pts)

  • Copy and paste the starter code into a new file called funFunctions3.cpp
  • Write the required functions as described by the prototypes and comments.
  • The functions should be written below main.
  • Then, run the code when you are finished to see if you wrote the functions correctly.
  • Check the test results and make any alterations to your functions as necessary.
  • When all of the tests pass, upload your code to Canvas.
/**
 *
 * CIS 22A
 */

#include <iostream>
using namespace std;


bool first10Last(int data[], int size);
//Given an array of ints, return true if 10 appears as
//either the first or last element in the array. The array will be size 1 or more.
//first10Last([1, 2, 10], 3) → true
//first10Last([10, 1, 2, 3], 4) → true
//first10Last([13, 10, 1, 2, 3], 5) → false

bool equalFirstLast(int array[], int size);
//Given an array of ints, return true if the array is size 1 or more,
//AND the first element and the last element are equal.
//equalFirstLast([1, 2, 3], 3) → false
//equalFirstLast([1, 2, 3, 1], 4) → true
//equalFirstLast([1, 2, 1], 3) → true

void printArray(int array[], int size);
//prints the contents of an array with a for loop
//see class notes for examples

void arrayPlus2(int array[], int size);
//Given an array of ints, add 2 to each element in the array
//return nothing. Remember arrays are automatically pass by reference
//arrayPlus2([1,2,3],3) -> [3, 4, 5]
//arrayPlus2([10, 30, 50, 79, 85], 5) -> [12, 32, 52, 81, 87]
//arrayPlus2([5], 1) -> [7]

void squareArray(int array[], int size);
//Given an array of ints, add multiplies each element in the array by itself
//return nothing. Remember arrays are automatically pass by reference
//squareArray([1,2,3],3) -> [1, 4, 9]
//squareArray([3, 5, 6, 8, 9], 5) -> [9, 25, 36, 64, 81]
//squareArray([5], 1) -> [25]


int main()
{
    int result;
    bool answer;
    string value;
   
    cout << boolalpha; //displays bools as true and false
   
    cout << "***Testing first10Last***"<< endl << endl;
    int array1[] = {1, 2, 10};
    const int SIZE1 = 3;
    answer = first10Last(array1, SIZE1);
    cout << "Should print true: " << answer << endl;
    int array2[] = {10, 1, 2, 3};
    const int SIZE2 = 4;
    answer = first10Last(array2, SIZE2);
    cout << "Should print true: " << answer << endl;
    int array3[] = {13, 10, 1, 2, 3};
    const int SIZE3 = 5;
    answer = first10Last(array3, SIZE3);
    cout << "Should print false: " << answer << endl << endl;

    cout << "***Testing equalFirstLast***"<< endl << endl;
    int array4[] = {1, 2, 3};
    const int SIZE4 = 3;
    answer = equalFirstLast(array4, SIZE4);
    cout << "Should be false: " << answer << endl;
    int array5[] = {10, 20, 50, 60, 80, 90, 10};
    const int SIZE5 = 7;
    answer = equalFirstLast(array5, SIZE5);
    cout << "Should be true: " << answer << endl;
    int array6[] = {1};
    const int SIZE = 1;
    answer = equalFirstLast(array6, SIZE);
    cout << "Should be true: " << answer << endl << endl;

    cout << "***Testing arrayPlus2***" << endl << endl;
    int array7[] = {1, 2, 3};
    const int SIZE7 = 3;
    arrayPlus2(array7, SIZE7);
    cout << "Should print 3 4 5: " << endl;
    printArray(array7, SIZE7);
    cout << endl;
    int array8[] = {10, 30, 50, 79, 85};
    const int SIZE8 = 5;
    arrayPlus2(array8, SIZE8);
    cout << "Should print 12 32 52 81 87: " << endl;
    printArray(array8, SIZE8);
    cout << endl;
    int array9[] = {5};
    const int SIZE9 = 1;
    arrayPlus2(array9, SIZE9);
    cout << "Should print 7: " << endl;
    printArray(array9, SIZE9);
    cout << endl << endl;

    cout << "***Testing squareArray***" << endl << endl;
    int array10[] = {1, 2, 3};
    const int SIZE10 = 3;
    squareArray(array10, SIZE10);
    cout << "Should print 1 4 9: " << endl;
    printArray(array10, SIZE10);
    cout << endl;
    int array11[] = {3, 5, 6, 8, 9};
    const int SIZE11 = 5;
    squareArray(array11, SIZE11);
    cout << "Should print 9 25 36 64 81: " << endl;
    printArray(array11, SIZE11);
    cout << endl;
    int array12[] = {5};
    const int SIZE12 = 1;
    squareArray(array12, SIZE12);
    cout << "Should print 25: " << endl;
    printArray(array12, SIZE12);
    cout << endl << endl;

    cout << "***End of Tests***" << endl;
   
    return 0;

}


Upcoming Assignments


~Good Luck Studying!~