Welcome to Lesson 18!


Learning Objectives
By the end of today's class, you should know...
  • What is the difference between pass by reference and pass by value?
  • How do you indicate a reference parameter?
  • What is a stream?
  • How to do you read and right from a file?

Announcements

  • Return midterms in last 5 minutes of class
    • As: 28 (8 100% scores)
    • Bs: 9
    • Cs: 3
    • Ds: 1
    • Fs: 2
    • No Shows: 1
  • If you got a C, D or an F, still time to turn your grade around!
    • Final exam worth 35% of the grade
    • Something about your approach needs to change!
      • Get more help?
      • Pay better attention?
      • Come to every class?
      • Start doing the homework?
      • Study!
      • Study more effectively?
  • Quiz next class - Functions and File I/O
    • Writing Functions
    • Calling Functions - Void vs Nonvoid
    • Pass by Reference vs Pass by Value
    • Writing Function Prototypes and Comments
    • One simple File I/O question
    • See Review Activities from Lesson 17, 18, 19
  • Lab 8 due Friday


Review Activity

1. Write the following functions:


Function 1
  • The function is named printGrade
  • It takes in a double for the score
  • It prints out the grade to the console as A, B, C, D, or F with a message, "The grade is: <grade>"
  • It returns nothing

Function 2

  • The function is named convertGrade
  • It takes in a double for the score
  • It determines if the grade is A, B, C, D, or F
  • It returns a char for the grade

Function 3

  • The function is named notString
  • It takes in one string parameter
  • It returns a new string where "not " has been added to the front.
  • However, if the string already begins with "not", it return the string unchanged.

2. Using the starter code below, call the above printGrade and convertGrade functions:

#include <iostream>
using namespace std;

int main() {
    double score;
    char grade;
    cout << "Please enter your score: ";
    cin >> score;
   
    //call printGrade here
    //Note: with printGrade, I can only display the grade to the console

    //call convertGrade here
    cout << "Your grade is " << grade << endl;
    //Note: with convertGrade, I can store the grade
    //and do more with it than display it. It is
    //stored for future use.

}


3. Write the comment and prototype for the below function:

double mpg(double miles, double gallons)
{
    return miles / gallons;
}


Value Parameters

  • There are two ways to pass arguments to parameters
  • All our functions so far have used value parameters
  • Value parameters are separate variables from the ones in main() (or another calling function)
  • Modification of value parameters does not affect the original caller's value when the function returns

How Value Parameters Work

  • During the function call, your program copies the argument's value into the parameter variable
  • The scope of value parameters is the same as the scope for a local variable
  • If the parameter is assigned a new value, only the local copy changes
  • When the function returns, your program discards any value assigned to a parameter variable
  • The following example program uses value parameters
  • What does this program output?

Example of Value Parameters

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

int mystery(int param) {
    cout << "param=" << param << endl;
    param = param * 2;
    return param;
}

int main() {
    int num = 2;

    cout << "At first, num=" << num << endl;
    int result = mystery(num);
    cout << "After calling, num=" << num << endl;
    cout << "And result=" << result << endl;

    return 0;
}


Reference Parameters

  • C++ has another parameter-passing mechanism known as call-by-reference
  • A reference parameter does not create a new variable, but refers to an existing variable instead
  • Any change in a reference parameter is actually a change in the variable to which it refers
  • We create a reference parameter by using an ampersand (&) between the parameter's type and name
    parameterType& parameterName
    
  • The following program shows an example of reference parameters
  • What is different?
  • What does this program output?

Example of Reference Parameters

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

int mystery(int& param) {
    cout << "param=" << param << endl;
    param = param * 2;
    return param;
}

int main() {
    int num = 2;

    cout << "At first, num=" << num << endl;
    int result = mystery(num);
    cout << "After calling, num=" << num << endl;
    cout << "And result=" << result << endl;

    return 0;
}

Call-By-Reference Details

  • What's really passed to the reference parameter?
  • A reference to the caller's original argument!
  • Essentially a reference parameter is another name for the original argument
  • With a reference parameter the code uses the original argument variable in calculations
  • Any change made to a reference parameter changes the original argument
  • Because C++ is passing variables, arguments for reference parameters must be variables and not constants



Mixed Parameter Lists

  • Parameter lists can include both value and reference parameters
  • As usual, the order of arguments in the list is critical
  • The following is a function signature with mixed parameter types:
    void mixedCall(int& par1, int par2, double& par3)
    
  • To call the function:
    int arg1 = 0, arg2 = 1;
    double arg3 = 2.2;
    mixedCall(arg1, arg2, arg3);
    
  • arg1 must be an integer type and is passed by reference
  • arg2 must be an integer type and is passed by value
  • arg3 must be a double type and is passed by reference

When to Use Reference Parameters

  • Reference parameters are usually more efficient than value parameters because they do not make copies of the parameters:
    • A program simply passes the memory address to the function
    • No new memory space is allocated and deallocated
  • Therefore, function calls using reference parameters usually operate faster
  • However, reference parameters restrict the arguments we can use for a function
  • Specifically, we must use a variable argument and not a literal or constant value
  • Usually, the best practice is to pass an object, like a String, by reference
  • Also, we should use value parameters unless a function needs to modify a parameter
  • The performance advantage of reference parameters for primitive types tends to be negligible
  • Thus, it is not worth restricting the call pattern of a function

Reference vs Value Video


Activity 18.1: Exploring Call by Reference (10 pts)

In this exercise we explore how call-by-reference parameters differ from call-by-value parameters.

Specifications

  1. Copy the following program into CodeBlocks and save it as swap.cpp:
    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;
    
    void swap(int var1, int var2);
    
    int main() {
        int num1 = 0, num2 = 0;
        cout << "Enter two integers: ";
        cin >> num1 >> num2;
    
        swap(num1, num2);
    
        cout << "After calling function:  "
             << num1 << " " << num2 << endl;
        return 0;
    }
    
    void swap(int var1, int var2) {
        int temp = var1;
        var1 = var2;
        var2 = temp;
    }
    
  2. Compile and run the starter program to make sure you entered it correctly. When you run the program, the output should look like this:
    Enter two integers: 1 2
    After calling function: 1 2
    

    Notice that num1 and num2 have the same values before and after calling the function swap(). Any value assigned to var1 and var2 have no effect on num1 and num2.

  3. Change your program by adding the four ampersands (&) circled below:

    The ampersands tell C++ to use call-by-reference when passing parameter values.

  4. Compile and run the modified program to make sure you made the changes correctly. When you run the program, the output should look like this:
    Enter two integers: 1 2
    After calling function: 2 1
    

    Notice that num1 and num2 have different values before and after calling the function swap(). Any value assigned to var1 and var2 change num1 and num2 respectively.

  5. Submit your final program source code to Canvas.


Streams and File I/O


About Program I/O
  • Program I/O = Program Input/Output
    • Input to and output from programs
  • Input can be from a keyboard, mouse or file
  • Output can be to a display screen, printer or file
  • Note that files can be both input and output devices for programs
  • Advantages of file I/O:
    • Data still exists after the program ends
    • Input can be automated (rather than entered manually)
    • Output from one program can be input to another
  • To store and retrieve data in a file, we need two constructs:
    • A file
    • A file stream object
  • We will look at files first

Files

File: a collection of data stored under a common name on a storage medium.

  • Files provide long-term storage of large amounts of data
  • Usually, you store files on durable storage mediums
    • Magnetic disks
    • Optical disks
    • Flash storage, like USB storage devices
  • Files are a single sequence of bytes

    Byte 0 Byte 1 Byte 2 ... Byte n−1 End-of-file marker

  • Since the data arranged as bytes, any type of data can be stored in a file
  • The operating system keeps track of the number of bytes in a file
  • Files must have a name
    • Naming requirements depend on the underlying operating system (OS)
  • The operating system organizes files into directories

Types of Files

  • All data in a file is ultimately just zeros and ones
  • Each binary digit can have one of two values: 0 or 1
  • A bit is one binary digit
  • A byte is a group of eight bits
  • These binary digits may represent integer values or text characters
  • It is up to the program using the file to understand the meaning and internal format of the data
  • In general, programs interpret data using two broad categories: text and binary

Text Files

  • In text files, the bits represent printable characters
  • Files are usually stored as one byte per character (ASCII)
  • Each line is delimited by end-of-line characters:
    • Macintosh (before OS-X): "\r"
    • Unix: "\n"
    • Windows: "\r\n"
  • An example of a text file is source code
  • We can read text files because each byte is interpreted by a program as textual characters
  • Some of these programs, like TextPad, then display the textual data to your computer's screen
  • Since there are many programs that read and display text, text files are called human readable

Binary Files

  • Data other than text is usually referred to as binary data
  • Each bit represents some type of encoded information
    • Such as program instructions or integer data
  • Binary files are easily read by the computer but not by humans
  • The following table compares binary and text values saved in a file
  • First we consider the value "1234" as ASCII codes and compare these bits to a binary value of 1234
  • As we can see, the bit patterns are different for the same data when stored as text or binary

Comparing Binary and Textual Data

Description Byte 0 Byte 1 Byte 2 Byte 3
"1234" as char's '1' '2' '3' '4'
"1234" as ASCII codes (bytes) 49 50 51 52
"1234" as ASCII codes (bits) 00110001 00110010 00110011 00110100
(int) 1234 as binary bits 00000000 00000000 00000100 11010010

Streams

Stream: a one-way transmission path that either delivers data to a destination (screen, file, etc.) or that takes data from a source (keyboard, file, etc.)

  • A stream connects a program to an I/O object
  • Input stream: an object that provides a sequence of bytes to a program
image depicting an input stream

  • Output stream: an object that accepts a sequence of bytes from a program
image depicting an output stream

  • cin and cout are input and output streams

File Streams

File stream: a one-way transmission path used to connect a program to a file.

  • File streams can be either input or output streams
  • File input streams receive data from a file
  • File output streams send data to a file
  • File I/O uses streams of type ifstream and ofstream
  • To declare a file input stream, we write code like:
    ifstream fin; //declares a file input stream
  • Similarly, to declare a file input stream we write code like:
    ofstream fout; //declares a file output stream
  • Each file your program uses will need a separate file stream object
Streams and Objects

  • Streams are objects and thus cin and cout are objects
  • Objects are special variables that can have a function associated with them
  • To call a function of an object, we use the dot operator
  • An example of using the dot operator is with cin is shown below
cin.fail();

Example of File I/O

  • Let us consider an example that reads from a file and writes to a file
  • The program reads from a file named infile.txt, which contains the following values:
    10
    20
    30
    
  • After summing the values, the program writes them to a file named outfile.txt
  • Consider the following code and try to identify:
    1. What is the name of the input stream?
    2. Which line opens a file for reading
    3. What is the name of the output stream?
    4. Which line opens a file for writing
    5. Which line reads data from the input stream?
    6. Which lines write data to the output stream?

Example Program to Read and Write Files


/**
    Reads three numbers from the file infile.txt,
    sums the numbers, and writes the sum to the
    file outfile.txt.
*/
#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 opening failed.\n";
        exit(-1);
    }

    ofstream fout;
    fout.open("outfile.txt");
    if (fout.fail()) {
        cout << "Output file opening failed.\n";
        exit(-1);
    }

    int first, second, third;
    fin >> first >> second >> third;
    fout << "The sum of the first 3\n"
         << "numbers in infile.txt\n"
         << "is " << (first + second + third)
         << endl;

    fin.close();
    fout.close();

    cout << "Processing completed\n";

    return 0;
}
Closing a Stream

  • After finishing reading and writing you should close the file streams
  • If you do not close an output stream, you may lose data stored in the output buffer
  • In addition, streams consume system resources and you should not keep open any more streams than needed

Procedure For File I/O

  1. Place the following include directives in your program file:
    #include <fstream>   // for file I/O
    #include <iostream>  // for cout
    #include <cstdlib>   // for exit()
    using namespace std;
    
  2. Declare names for input and output streams like:
    ifstream fin;
    ofstream fout;
    
  3. Connect each stream to a file using open() and check for failure:
    fin.open("infile.txt");
    if (fin.fail()) {
        cout << "Input file failed to open.\n"; exit(-1);
    }
    
    fout.open("outfile.txt");
    if (fout.fail()) {
        cout << "Output file failed to open.\n";
        exit(-1);
    }
    
  4. If there is a failure, we need to check that the input file is stored in the same directory that the .cpp file is executing.
  5. Read or write the data:
    • Read from a file with fin like using cin:
      fin >> first >> second >> third;
      
    • Write to a file with fout like using cout:
      fout << "first = " << first << endl;
      
  6. Close the streams when finished reading and writing:
    fin.close();
    fout.close();
    

More Information


How to Save Your Files on the Mac

  • For the Mac, CodeBlocks will require you to save your txt files in your user directory rather than in the same folder as your program
  • Your user directory is the one that typically has your name. On my Mac, it is named parrishj.
  • You can find this directory by selecting Go -> Home

How to Save Your Files Using Eclipse

  • If you are using Eclipse for your assignments in this class, you can simply save the file in the same project folder as your program (not under src)
  • Right click on the project folder in the project explorer (right side bar)
  • Then, go to New->File from the drop down menu that appears
  • Name your file using the extension .txt
  • Note: if your project explorer is hidden, go to the following: Window->Show View->Other...->General->Project Explorer
     

Activity 18.2: Two Numbers

  • In this exercise we write a program that copies two numbers from an input stream to an output stream.
  • Copy the following program into a C++ file, save it as copytwo.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;
    }
    
  • Then, let's create a text file to test our program. Open up Notepad or another text editor (Word is not a good choice). Name the file infile.txt. In the file, add a list of numbers each on their own line, like this:
10
20

  • Important: You need to save this file in the same directory that you are executing your C++ files.
  • We will read from this file after writing our program.

  • Place the following include directives in your source code file:
    #include <iostream>  // for cout
    #include <fstream>   // for file I/O
    #include <cstdlib>   // for exit()
    using namespace std;
    
  • Inside main(), declare names for the input and output streams:
    ifstream fin;
    ofstream fout;
    
  • Add code to connect each stream to a file using open() and check for failure:
    fin.open("infile.txt");
    if (fin.fail()) {
        cout << "Input file failed to open.\n";
        exit(-1);
    }
    
    fout.open("outfile.txt");
    if (fout.fail()) {
        cout << "Output file failed to open.\n";
        exit(-1);
    }
    
  • Add statements to read two numbers from the input stream. For example, here is possible code for reading the first number:
    int first;
    fin >> first;
    
  • Add statements to write the two numbers to the output stream. For example, here is possible code for writing the first number:
    fout << "first = " << first << endl;
    
  • Close the streams when finished reading and writing:
    fin.close();
    fout.close();
    
  • Compile and run your modified program to make sure you made the changes correctly.

    Notice that you do not see any output on the screen for file reading or writing. The output stream wrote the program output to the output file.

  • Save your program source code file to submit to Canvas

Listing of copytwo.cpp

copy two program


Wrap Up

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


Upcoming Assignments


~See You Thursday!~