"

7 C++ I/O Streams

Hussam Ghunaim, Ph.D.

projectSkeletonLearning Objectives

At the end of this chapter, you will be able to:-

  • Explain what Classes and Objects are and how to differentiate between them
  • Use I/O Console Objects to solve real-life problems
  • Use I/O File Objects to solve real-life problems
  • Formatting I/O Streams
  • Practice using Low-Level I/O Functions

Introducing Classes and Objects

Up to this point, you have mainly declared and initialized variables with primitive data types, like int, double, and others. We call these types primitive because they are capable of holding only a single datum, such as a number or a character. This works fine for simple applications, but in real-world applications, we often need larger data structures that can hold more data and provide operations on them, that is, classes. One way to understand classes is to think of them as custom data types or ‘tiny programs’. You have already used one of these classes, the string class. In Chapter 2, you used several of this class’s member functions, such as length(), find(), and replace(), among others.

Objects are instances created from classes, Figure 01. The vertical dots in this figure denote the possible presence of additional code. Classes are blueprints that define the structure and behavior of objects, including data members (we call them either variables or fields; both words are synonyms) and member functions (methods). However, a class itself is not executable code. To utilize the structure and behavior defined by the class, we instantiate the class by creating an instance of an object from it. The created object is not exactly a ‘copy’ of the class, but an ‘instance’ that follows the structure and behavior defined by the class. Once an object is instantiated, we can assign data to its fields and call its member functions.

ch07_fig01
Figure 01: Creating an instance of an object from a class.

I/O Console Objects

In this chapter, we will focus on stream objects. Later, you will learn how you can write your own classes. These objects are called streams because they are specifically designed to control data reading and writing. Technically speaking, computers read and write data as streams of data. As you already know, computers can read from and write to many input and output devices. Each input and output device has a specific input or output stream associated with it.

In all previous chapters, you have used the cout output stream that prints data to the console and cin input stream that reads data from the console. These are a special kind of objects because they do not need to be declared or instantiated. These are standard I/O streams that are ready to be used right away.

I/O File Objects

Writing programs always involve working with data input and output. So far, we have managed to enter the needed data manually. But imagine if we need to enter a large amount of data every time we run our program. Further, imagine if we want to keep the output that results from running the program. For now, all outputs will disappear once the execution of a program is terminated. Files come to the rescue. Working with files is fantastic to serve both needs: to read data that programs need to function properly, and to save outputs for further use. Therefore, it is an essential skill to become comfortable working with files.

As you expect, there is a stream to read from a file and another stream to write to a file. Working with files requires two operations: declaring the stream and then instantiating the stream.

ifstream myInputFile; // declaring the file input object
myInputFile.open(“inputFile.txt”); // instantiating the file input object
ofstream myOutputFile; // declaring the file output object
myOutputFile.open(“outputFile.txt”); // instantiating the file output object

In the declaration line, we use the class name, which is effectively the type name, to declare a file input stream object called myInputFile. This operation is similar to all primitive declarations that you have already done. For example, when writing int myVar; you are declaring a variable named myVar with the specified type int. The same thing goes for declaring the file output stream object. However, the initialization looks different. In primitive types like int, after declaring the variable, you can simply initialize it by assigning a value to it, like myVar = 0; When working with objects, we must use their member functions to initialize them.

The open function is a member function of both input and output streams, but of course, they are different functions. To specify which open function we intend to call, we use the dot . notation. In the provided code, we use the member function open from the input stream to attach the inputFile.txt to the input stream. Similarly, we use the member function open from the output stream to attach the outputFile.txt to the output stream.

Note that we use two different files for input and output to make it easy to differentiate between them; however, technically, it is possible to use the same file for input and output. C++ is a powerful language that allows you to read and write to virtually any file type. However, we will focus in this book on text files because they are the easiest type of files to work with.

Example 01

This example is about counting how many words are in the input file and saving the result in the output file. The location of files is very important. You need to specify exactly where the files are located. Of course, both files can be located at the same location or at different locations. The problem here is that files’ addresses are written differently on different systems. On Windows, the backslash \ is used; however, on Unix or Mac systems, the forward slash / is used. The one that can be used in C++ code is the forward slash. Therefore, if you are using a Windows system, you cannot use the backslash alone because it will confuse the C++ compiler and be interpreted as the escape character. If you still want to use the Windows file address style, you must replace every backslash with double backslashes to avoid this conflict. In the example, the two methods are used for illustration, but you can choose your preferred way of writing files’ addresses.

Another solution to this problem is to put all files in the same location as the source code file and avoid adding file paths altogether. This method will be used throughout the chapter.

In the provided code, change the files’ addresses corresponding to your system. Then, run the example code and explain the results.

ch06_exa01

First of all, when you run the code, you will notice that nothing has been printed on the console. This is expected as there is no code to do so. Even we did not include the <iostream> library because, in this particular example, we do not intend to use either cout or cin streams.

Second, assuming you entered your filenames along with their locations correctly, you should have the total number of words printed in the output file. When creating the input file, add a couple of words or sentences to double-check if the code works correctly.

Third, notice how the insertion operator << and the extraction operator >> work with files’ streams exactly in the same way as they work with console streams. In the while loop condition, every time the condition is checked, a word will be read from the input file and saved in the word variable.  If a word is successfully read, the condition returns true, causing the loop to continue. When reaching the end of the file,  reading a word fails, causing the condition to return false and terminating the loop.  After the loop terminates, a message will be sent to the output file along with the total number of words saved in the wordCount variable.

Finally, as a good programming practice, you must always close all open streams for many reasons, such as releasing allocated resources and avoiding data corruption.

Example 02

Run the provided code, examine both input and output files, and explain the results.  Before doing that, you must create the input file ‘rawData.txt’ and add a few integers and decimal numbers to it, such as 5 0 7.2 8 0 3 3.14 0 2 9.8. If you forgot to create the output file, it will be created automatically for you.

In this example, we added code to handle errors when working with files. Errors can occur for many reasons, such as misspelling files’ names, corrupted files, and so on. The is_open() function is a member function in both streams, the input and the output. If a file cannot be opened, the is_open() function will return false. If this occurs, the if-statement condition, !inputFile.is_open() will be true, causing the message “Unable to open input file.” to print out to the console. Similar logic applies to the output file as well. Note that we are using both file streams and console streams.

The while loop condition will perform two tasks. First, it will read numbers from the input stream and save them one by one in the number variable. The second task is to return true if the read operation was successful and initiate the following iteration until the condition returns false, thereby terminating the while loop. For every iteration when the variable number gets a new value, this value is used to perform the four arithmetic operations. At the end of the loop, the variables: addition, subtraction, division, and multiplication will have their final results.

After the while loop terminates, all results will be printed out to the console along with appropriate messages. Finally, both streams will be closed.

ch07_exa02

Exercise 01

Modify example 1 to allow the code to count the number of characters instead of words.

Hint: You only need to make a tiny change!

Exercise 02

Write a program that reads a text file that contains both words and numbers, and then counts how many words and numbers are in the file. The program should meet the following specifications:

1) Both input and output files should be checked to ensure they were opened correctly. If not, an error message must be printed out to the console.
2)  Use the isdigit() function found in the <cctype> library to check whether a character is a number or not.
3)  The results should be printed out to an output file like this: “The input file contains ….. numbers and ….. words.”
4)  At the end of the program execution, print this message to the console: “File operation completed successfully!”.

Formatting I/O Streams

In Chapter 2, you have learned how to use some manipulators to format the output console stream cout. You can think of manipulators as special functions that can be called to manipulate the stream behavior, for example, setw(), left, right, fixed, and setprecision().

Example 03

Run the code and explain the results. To do that, you need to create two text files, inFile.txt and outFile.txt. The inFile.txt must contain some unformatted data to work on, like,

Quiz01 Quiz02 Quiz03 Average
12.5 16 15.8 14.76666666
9 19.9 16 14.9666666
19.5 17.7 18 18.36666666

The code will print the unformatted data to the console and write the formatted data to the output file.

When reading from an input stream, an internal marker is used to keep track of the current reading position. This marker advances every time a successful reading operation is executed. The stream begins in a ‘good‘ state if opened successfully. It remains in this state until it encounters an issue, such as reaching the end of the file, at which point the eof flag is set. The stream’s status can be checked at any time to determine if operations have been successful or if any errors have occurred.

As usual, we first must declare and instantiate the file streams, lines 10 to 16. Lines 19 to 24 print the content of the input file to the console unformatted. This is done using a while loop. This loop continues as long as the input stream is in a valid state by checking the condition while (inputFile >> word). The loop reads the file word by word, printing each word to the console. After each word is read, we use the peek() function to check if the next character is a newline. If it is, we print a new line to the console, ensuring that the output maintains the line structure of the input file. This process continues until the end of the file is reached, at which point the stream enters a fail state, terminating the loop.

After reading the file once, the stream still has all the input, but the reading marker is positioned at the end of the stream. Therefore, we can not read it again. To read the stream again, we call inputFile.clear() to reset any error flags and inputFile.seekg(0) to move the read position back to the beginning of the stream. The second while loop reads the input stream for a second time, writing the formatted output to the output file. The output file stream is set to use fixed-point notation, always show the decimal point, and use 2 decimal places for floating-point numbers, lines 31 to 33. As it reads each word, the code checks if the first character is a digit. If so, it’s converted to a double using stod() (string to double) function and written as a number; otherwise, it’s written as a string. This step is important because words are read from the input stream as strings and will not be affected by the formatting settings in lines 31 to 33. These settings only apply to numbers. All output is left-aligned in fields 15 characters wide. Newlines are preserved from the input file structure.

ch07_exa03

Example 04

In this example, we will do a similar formatting as we did in example 03 with some additions. First of all, run the code and try to explain the outcomes to familiarize yourself with the code. To run the code, you need to create an input file that has the following data without formatting.

First Name Last Name Score Letter Grade
John Doe 85
Jane Smith 92
Alice Johnson 78
Bob Brown 88
Carol Davis 95
David Wilson 67
Emma Taylor 74
Frank Anderson 81
Grace Thomas 90
Henry Jackson 59

Instead of entering files’ names hard-coded, we will let users input their chosen file name, lines 56 and 57.  Of course, the file name should include the file extension, which is .txt. Then, we declare and initialize both the input and output streams’ objects. You have already seen that whenever you write data to the output file, all preexisting contents will be overwritten. As we are using, in this example, the same file as an input and output file, we must be able to keep the preexisting content and append the new data below the older data. To do this, we use the open mode flag ios::app when initializing the output stream, line 61.

Following the best programming practices, we should not put all the code in the main function; rather, other functions must be created to handle different tasks. Therefore, we created three functions: Grades, displayUnformattedData, and writeFormattedData. The Grades function takes a double score value and returns the corresponding grade letter. displayUnformattedData function takes the input stream as a parameter passed by reference. To read from this input stream, it uses the getline function from the <string> library.  getline function takes two parameters: the input stream and the variable used to store each line. while loop will keep iterating while getline reads lines successfully until hitting the end of the file, when the loop condition fails, terminating the loop.  In each iteration, the line is printed out to the console using the cout stream.

The writeFormattedData function takes both the input and output streams as parameters passed by reference. Lines 30 to 33 print the header of the formatted table. To avoid duplication, line 36 skips reading the table header from the input file by simply reading the first line and doing nothing with it. The while loop condition reads the first three words in every line from the input stream and saves them into firstName, lastName, and score variables sequentially. letterGrade variable gets its value by calling the Grades function. Several manipulators are called to format the output in the way we want. ignore function in line 45 is called to clear any remaining characters in the line to ensure that in the next iteration, the reading will start from the second line. ignore takes two parameters: the maximum number of characters to be cleared and the end-of-line character. ignore will stop clearing the stream when hitting either of those two parameters’ values. The number 1000 is an arbitrary value chosen here to be large enough to clear all characters remaining in any specific line.

ch07_exa04

Exercise 03

Write a program that does the following:
1) Read a text file containing the following unformatted data:
WeekDay       Sat   Sun Mon         Tue   Wed     Thu Fri             Average
week01   85     92    81   79     95    86              90
week02  81                93         77   64             89   96            82
week03               71         73 87       85    94        88    79
week04 83     97                      91    80 82               91    84
2) Write a function that prints out the unformatted data to the console. This function takes the input stream as a parameter passed by reference.
3) Write a function that formats the data in a table with boundaries using the ‘|‘ and ‘ ‘ characters.  Calculate the average for each week and add the values to the same table. The formatted data must be appended under the unformatted data in the same file. This function takes both the input and output streams as parameters passed by reference.
4) The user must be allowed to enter the full input file name.
5) In the formatted table, all columns must be left-aligned except the Average column, which must be right-aligned.
6) The average values must be formatted to have only two decimal places.
7) Before exiting the program, write to the console this message: “The formatted data is written to the output file, please check!”.
Hints:
  • There are many similarities between this exercise and example 02 that allow you to reuse some of its code.
  • You can declare and instantiate either input or output streams in one line:
    • ifstream inputFile(fileName);
    • ofstream outputFile(fileName, ios::app);

Exercise 04

1. What are manipulators in the context of I/O streams?
2. How does the internal marker of an input stream work?
3. What happens when an input stream reaches the end of a file?
4. How can you reset an input stream to read from the beginning again?
5. What is the purpose of the peek() function when reading from a file?
6. How can you append new data to an existing file instead of overwriting it?
7. What does the ignore() function do in the context of input streams?
8. How can you format floating-point numbers to always show a specific number of decimal places?
9. What is the purpose of the stod() function?
10. How can you ensure that words read as strings are not affected by numeric formatting settings?

Low-Level I/O Functions

The console and file streams we have discussed so far offer a powerful way to read and write data. These streams are convenient because they allow us to use extraction and insertion operators, which automate tasks such as skipping spaces and end-of-line characters. However, in some cases, we might prefer more control over the data being read or written. C++ provides lower-level functions, such as get(), put(), and putback(), which allows for this level of control.

Example 05

Run the given code and explain the outputs. We use the cin to read from the input stream. However, cin is designed to stop reading when encountering the first white space. This can be convenient for some scenarios but not desirable for others. In this code, we use the get() method to read everything from the input stream. This includes white spaces, tabs, special characters, and even the end-of-line character ‘\n’, which is invisible.

In this example, the code reads an entire line of text from the console and prints out the reversed text. The line can contain letters, numbers, tabs, and special characters. To test whether the code works as expected or not, use this line: “This is    a test                 line_ ( 234 ) !“. Note: The long space is created by a tab.

We use an array to store the line characters and later print them out in reverse. The while loop condition has 3 parts. The first part, cin.get(ch), returns true as long as the stream has characters in it. The second part, ch !=’\n’, returns false when reading the end-of-line character. The last part tests whether the array becomes full or not. In the for loop, we use the put() function to put characters into the output stream in a reversed order. Note that get() is a member function of every input stream, like cin and ifstream, and put() is a member function of every output stream, like cout and ofstream.

ch07_exa05

Example 06

Run the given code and explain the outputs. To do so, create an input file containing dollar amounts and other text. For example:

The concert tickets cost \$50 each, and I plan to buy 4 for my friends. After spending \$75 on dinner, we’ll head to the show, which features 10 opening acts. If I buy a souvenir for \$85, that will leave me with \$40 for snacks. Overall, I have saved \$400 for the event, hoping to enjoy a great night out. I’m excited to spend around \$400 on this unforgettable experience!

This example shows how you can manipulate inputs in any way you wish. The code processes the input file “exa06.txt” and writes the processed output to the same file, appending the new content to the end.
The outer while loop will keep reading the input stream character by character until the end of the file is reached, when the condition inputFile.get(ch) returns false. The first if-statement on line 21 checks if the read character is a ‘\$’. If it is, the code will surround the number, including the ‘\$’, with parentheses; otherwise, the else statement on line 36 puts the character as-is to the output stream using the put() function.
The second if statement on line 24 reads the character right after the dollar sign and checks if it is a digit. When both conditions in the if-statement are true, the do-while loop will read the entire number regardless of how many digits are in it. Note that the do-while loop does not use curly braces because it has only one statement.
After the inner do-while loop terminates, line 28 puts the closing parenthesis into the output stream. Line 30 checks if the end of the file has been reached, and if it has, the outer while loop terminates.

ch07_exa06

Example 07

Run the given code and explain the results. When you run this code, line 7 will execute normally, asking for your first name initial. Line 8 will read your entry. However, when you are asked to enter your last name initial, you will miss the opportunity to respond, and the program terminates immediately.

What happens here is that when reading input using the extraction operator >>, it stops reading at the first space, tab, or newline it encounters. However, the input stream is not empty; it still contains the newline character ‘\n’ as a leftover. Although invisible, this character is still there.

Thus, when we try to read the last name initial in line 11, it actually reads this leftover character from the previous operation. This causes the system to think it has already executed the line of code completely and continues running the remaining lines.

This problem can be solved in two ways:

  1. Avoid reading the input stream using the get() function after reading the same stream using the extraction operator. If you rearrange the code in this example to read the first initial using the get() function and then read the second initial using the extraction operator, it will work correctly.
  2. Use the cin.ignore(1000, ‘\n’) function before reading the input stream with the get() function. This ensures that the stream is cleared of any leftover characters from previous operations, as we used in example 4, line 45.

ch07_exa07

Exercise 05

Modify the example 05 code to read and write to the same file.
Hint: All you need to do is replace console streams with file streams.

Exercise 06

In example 06, we wrote code to detect monetary numbers and add parentheses around them. The logic was checking for the \$ to distinguish the monetary numbers from everything else. In this exercise, you will use similar logic to sum all detected monetary numbers by assuming that monetary numbers must start with \$ sign. The result should be printed out to the console.  Create an input text file that contains this text as an example to test your code:

Students Planner for 2024/2025 Academic Year
————————————————————–
Attending college requires significant financial investment. The average tuition for a 4-year public university is around \$25,000 per year. In addition to tuition, students can expect to spend \$1,200 on textbooks and supplies each semester. Housing, food, transportation, and entertainment costs can roughly add another \$15,000 annually, depending on the student’s lifestyle. Students should plan to spend 15-20 hours per week on studying and 10-15 hours per week on entertainment and fun activities. Most universities follow a 4-month semester system, with each semester divided into 16 weeks of instruction and exams.

The challenge in this exercise is that when reading from a text file, we need a way to convert detected monetary numbers into integers. For simplicity, we will assume all monetary numbers are integers. However, if you are interested, you can find a way to work with decimal numbers as well. When a monetary number is detected, and the first digit is stored in a variable called ch, performing the subtraction ch – ‘0’ converts the character into its integer value. To clarify, remember that all characters are encoded using the ASCII encoding system; thus, if ch = ‘5’, then ch – ‘0’ equals 53 – 48 = 5.  Now, we need to give this digit its correct value by using something similar to this line:

currentAmount = currentAmount * 10 + (ch – ‘0’);

Example: Converting the string “123” to the integer number 123. Suppose the code is reading the characters ‘1’, ‘2’, and ‘3’ one by one from the input file from left to right. Initially, we have currentAmount = 0.
1) Reading ‘1’ and saving it in ch, then performing ch – ‘0’ = ‘1’ – ‘0’ = 49 – 48 = 1.
2) Run currentAmount = currentAmount * 10 + (ch – ‘0’) which results to currentAmount = 0 * 10 + 1 = 1.
3) Reading ‘2’ and saving it in ch, then performing ch – ‘0’ = ‘2’ – ‘0’ = 50 – 48 = 2.
4) Run currentAmount = currentAmount * 10 + (ch – ‘0’) which results to currentAmount = 1 * 10 + 2 = 12
5) Reading ‘3’ and saving it in ch, then performing ch – ‘0’ = ‘3’ – ‘0’ = 51 – 48 = 3.
6) Run currentAmount = currentAmount * 10 + (ch – ‘0’) which results to currentAmount = 12 * 10 + 3 = 123 which is the final value.

Character Functions

Character functions are designed to manipulate individual characters, such as isupper, islower, isalpha, isdigit, isspace, tolower, and toupper. Table 01 provides further details. To use these functions, you need to include the <cctype> library.

Table 01: Character functions imported from <cctype> library.
Function Input Type Output Type Brief Description Example Usage
isupper char bool Returns true if the character is an uppercase, otherwise, returns false. isupper(‘A’) returns true.
islower char bool Returns true if the character is a lowercase; otherwise, returns false. islower(‘D’) returns false.
isalpha char bool Returns true if the character is a letter of the alphabet; otherwise, returns false. isalpha(‘*’) returns false.
isdigit int bool Returns true if the character is a digit (0-9); otherwise, returns false. isdigit(‘5’) returns true.
isspace char bool Returns true if the character is a space; otherwise, returns false. isspace(‘ ‘) returns true.
tolower char char Converts an uppercase letter to its lowercase equivalent. If the character is not an uppercase letter, it returns the character unchanged. tolower(‘A’) returns ‘a’.
toupper char char Converts a lowercase letter to its uppercase equivalent. If the character is not a lowercase letter, it returns the character unchanged. toupper(‘a’) returns ‘A’.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Example 08

Run the given code and explain the results. To do so, create an input file containing this text or any other similar text:

Hello World! 123 SeCreT MeSsAgE 456. ThIs Is A lOnGeR eXaMpLe 789. NoW wE hAvE mOrE tExT tO tEsT 012. UpPeR aNd LoWeR cAsE 345. DiGiTs AnD sPaCeS 678. PuNcTuAtIoN!@# %^ &*( TeStInG 901.

Note that in this example, we use the fail() stream member function to check whether the file opened correctly. In previous examples, we used the is_open member function, which serves a similar purpose. However, the fail() function can also check for errors in other operations beyond opening files, such as reading and writing errors. Additionally, we use the exit(1) function when an error is detected in the stream. Calling the exit(1) function immediately terminates the entire program. In previous examples, we simply used the return statement, which terminates only the current function, allowing the calling function to continue running. Conventionally, exit(0) indicates that the program completed its execution successfully, while any non-zero value signifies that an error has occurred.

Most of the code is straightforward and self-explanatory. The only exception is line 21, where we use the only ternary operator in C++ that has this syntax:

condition ? expression_if_true : expression_if_false;

This usage makes the code more compact and clearer. First, the if-statement in line 21 checks if the character c is alphabetical. If this is true, we continue to run the ternary operator; otherwise, the code continues to the following if-else statement. In the ternary operator, we run the condition isupper(c). If it returns true, we run tolower (c). Otherwise, we run toupper (c). Whatever lettercase is returned for the character c will be appended to the string variable decoded.

Lines 26 and 27 are used to count how many uppercase and lowercase letters the text has. They do that by calling the back() function that returns the last character in the variable decoded.

ch07_exa08

Wrap up

This chapter has provided a comprehensive overview of essential C++ concepts, focusing on classes, objects, and input/output operations. We began by exploring the fundamentals of object-oriented programming in C++, introducing classes as blueprints and objects as their instantiations. This foundational knowledge sets the stage for more advanced programming paradigms.

Our discussion then shifted to input and output operations, covering both console and file I/O. We examined the standard streams `cout` and `cin` for console operations, as well as `ifstream` and `ofstream` for file handling. Emphasis was placed on the importance of proper stream management, including initialization, usage, and closure.

The chapter also delved into more advanced I/O techniques. We explored various manipulators for output formatting and low-level I/O functions for finer control over data streams. Additionally, we covered character manipulation functions, basic error handling techniques, and methods for stream manipulation. These topics are crucial for developing robust and efficient C++ programs.

By mastering these concepts, you’ve significantly expanded your C++ programming toolkit. These skills form the backbone of many sophisticated applications and will prove invaluable as you tackle more complex programming challenges. As with any programming skill, regular practice will be key to fully internalizing these concepts and applying them effectively in your future projects.

Answer Key

Exercise 01:

The entire code will be similar to the example 01 code. The only change that you need to make is to change the declaration string word to char character. This will force the while loop condition inputFile >> character to read characters instead of words.

Exercise 02:

ch07_exe02

Exercise 03:

ch07_exe03

Exercise 04:

1. Q: What are manipulators in the context of I/O streams?
A: Manipulators are special functions that can be called to manipulate stream behavior, such as setw(), left, right, fixed, and setprecision().

2. Q: How does the internal marker of an input stream work?
A: The internal marker keeps track of the current reading position in the stream. It advances every time a successful reading operation is executed.

3. Q: What happens when an input stream reaches the end of a file?
A: When an input stream reaches the end of a file, the eof flag is set, and the stream enters a fail state.

4. Q: How can you reset an input stream to read from the beginning again?
A: You can reset an input stream by calling inputFile.clear() to reset any error flags and inputFile.seekg(0) to move the read position back to the beginning of the stream.

5. Q: What is the purpose of the peek() function when reading from a file?
A: The peek() function is used to check the next character in the stream without advancing the read position. In the example, it’s used to check for newline characters to maintain the line structure of the input file.

6. Q: How can you append new data to an existing file instead of overwriting it?
A: You can use the open mode flag ios::app when initializing the output stream to append new data to the end of an existing file.

7. Q: What does the ignore() function do in the context of input streams?
A: The ignore() function clears any remaining characters in the current line of the input stream. It takes two parameters: the maximum number of characters to clear and the end-of-line character.

8. Q: How can you format floating-point numbers to always show a specific number of decimal places?
A: You can use the fixed manipulator to use fixed-point notation and the setprecision() manipulator to set the number of decimal places. For example: outFile << fixed << setprecision(2);

9. Q: What is the purpose of the stod() function?
A: The stod() function converts a string to a double. It’s used when reading numeric data from a file as strings and converting it to actual numeric types.

10. Q: How can you ensure that words read as strings are not affected by numeric formatting settings?
A: Numeric formatting settings only apply to numbers. Words read as strings need to be explicitly converted to numbers (using functions like stod()) before they will be affected by numeric formatting.

Exercise 05:

ch07_exe05

Exercise 06:

ch07_exe06

End of Chapter Exercises

1) What is the main limitation of primitive data types in C++?

a) They are too complex for simple applications
b) They can hold only a single datum
c) They cannot be used in real-world applications
d) They don’t have member functions

2) How can classes be understood in simple terms?

a) As custom data types or ‘tiny programs’
b) As primitive data types
c) As complex data structures
d) As executable code

3) What is the relationship between a class and an object?

a) A class is an instance of an object
b) An object is a copy of a class
c) A class is a blueprint, and an object is an instance created from it
d) Objects and classes are the same thing

4) What components do classes typically include?

a) Only data members
b) Only member functions
c) Both data members and member functions
d) Neither data members nor member functions

5) What happens when an object is instantiated from a class?

a) The class becomes executable code
b) The object becomes a blueprint
c) The object becomes an exact copy of the class
d) We can assign data to the object’s fields and call its member functions

6) What are stream objects specifically designed for?

a) Controlling file permissions
b) Managing memory allocation
c) Controlling data reading and writing
d) Handling network connections

7) Which of the following is NOT a standard I/O stream in C++?

a) fstream
b) cout
c) cin
d) None of the above

8) What is the correct way to declare a file input stream object?

a) ifstream myInputFile;
b) ofstream myInputFile;
c) fstream myInputFile;
d) inputstream myInputFile;

9) Which operator is used to read data from an input file stream?

a) <<
b) ->
c) ::
d) >>

10) What function should be called to check if a file was opened successfully?

a) open()
b) is_open()
c) check_open()
d) file_status()

True/False Questions:
11) The cout and cin streams need to be declared and instantiated before use.
12) C++ allows reading from and writing to the same file.
13) The backslash character () can be used directly in file paths on all operating systems in C++ code.
14) The insertion operator (<<) is used for writing data to output streams.
15) The is_open() function returns true if a file cannot be opened.
16) Write a program that reads a text file and counts how many words contain vowels and how many words do not contain vowels. The program must check if the input file was opened correctly and print out the results to the console.
17) Write a C++ program to read a text file and write all words that have vowels to an output file called “wordsWithVowels.txt”, and write all words without vowels to a file called “wordsWithoutVowels.txt”. Only the input file must be checked to see if it was opened correctly. The user does not need to create the output files, as they will be created automatically by the system.
18) Write a program that reads an input file and counts how many times a user-specified word appears in the file. If the word does not exist in the file, display an appropriate message to the console. The result should be printed to the console.
19) What is the purpose of manipulators in C++ I/O streams?

a) To control the formatting of input data
b) To manipulate the internal state of the stream
c) To handle file operations
d) To read and write data to/from files

20) How does the peek() function work when reading from a file stream?

a) It reads the next character from the stream and advances the read position
b) It checks the next character without advancing the read position
c) It returns the current read position
d) It sets the read position to the beginning of the file

21) What happens when an input stream reaches the end of a file?

a) The eof flag is set
b) An exception is thrown
c) The stream is automatically closed
d) The stream remains in a good state

22) How can you append data to an existing file instead of overwriting it?

(a) Use the ios::binary flag when opening the output file
(b) Use the ios::out flag when opening the output file
(c) Use the ios::in flag when opening the output file
(d) Use the ios::app flag when opening the output file

23) What is the purpose of the stod() function?

a) To read a line from a file
b) To convert a double to a string
c) To convert a string to a double
d) To write a line to a file

True/False:

24)After reading the file once, the stream can be read again without resetting the reading marker.

25) The ignore function is used to clear any remaining characters in the line to ensure the next iteration starts from the second line.
26) left, right, and precision manipulators can only be used to format cout stream.

27) We must import the <iostream> library to be able to use the getline() function.

28) To prepare the input stream to be read for a second time, we can use the clear() and seekg(0) member functions.

29) Write a C++ program that reads a list of integers from a file named “numbers.txt” and outputs the integers to the console, ensuring that each integer is right-aligned in a field of width 10. Use the setw() manipulator for formatting. Include code to handle any potential errors. Use this suggested input data to test your program:
5
12
123
4567
890
23456
789012
3
999999
42

30) Create a C++ program that reads from a file named “data.txt” and prints the contents to both the console and a new file named “output.txt.” Include code to handle any potential errors.

31) Develop a C++ program that reads a file “grades.txt” containing floating-point numbers. The program should compute the average of these numbers and write the result to a file “average.txt”, formatting the output to show exactly two decimal places. Include code to handle any potential errors. Use this suggested input data to test your program:
85
90.0
76.3
88.44
92.7
78
95.555
81.2
65.1
99.99
70

32) Write a C++ program that reads a file “students.txt” containing student names and scores. The program should output a formatted table to the console, showing names left-aligned in a field of width 20 and scores right-aligned in a field of width 10. Scores should have only one decimal place. Each column should have a header. Include code to handle any potential errors. Use this suggested input data to test your program:
Alice 89
Bob 76.25
Charlie 92.5
Diana 85
Ethan 78.75
Fiona 95.0
George 67.5
Hannah 88.1
Ian 79.0
Jasmine 91.333

33) Implement a C++ program that processes a file named “weekly_data.txt” containing weekly scores. The program should output the unformatted data to the console, then reformat the data into a structured table with boundaries (using ‘|’ and ‘-‘) and append it to the same file. The table should include a third column titled “Status.” If the score is greater than 100, the status will be “verified”; otherwise, it will be “unverified.” Scores must be formatted to two decimal places and aligned to the right, while the weekly data should also be right-aligned. The Status column should be aligned to the left. Include code to handle any potential errors. Use this suggested input data to test your program:
week01 85.05
week02 92
week03 78.25
week04 900
week05 88.75
week06 761
week07 84.3333
week08 901.1
week09 89.999
week10 182

34) Which of the following functions is used to read a single character from the input stream, including white spaces and special characters?

a) cin >>
b) cin.get()
c) cin.put()
d) cin.ignore()

35) What is the purpose of the put() function in C++?

a) To read a character from the input stream
b) To write a character to the output stream
c) To skip spaces and end-of-line characters
d) To clear the input stream

36) In Example 05, what does the while loop condition cin.get(ch) check for?

a) If the input stream is empty
b) If the character read is a newline character
c) If the stream has characters in it
d) If the array is full

37) What problem does Example 07 illustrate when using the extraction operator >>?

a) It stops reading at the first space, tab, or newline
b) It reads all characters, including white spaces
c) It clears the input stream
d) It reads characters in reverse order

38) How can the issue in Example 07 be resolved when reading input using the extraction operator >>?

a) By using the put() function
b) By using the cin.clear() function
c) By using the cin.get() function
d) By using the cin.ignore() function

True/False questions:

39) The cin function stops reading input at the first whitespace character when using the extraction operator >>.
40) The ignore() function is used to clear leftover characters from the input stream in the context of this chapter’s examples.
41) Character functions like isupper and isdigit require the inclusion of the <string> library to be used.
42) The putback() function is used to push a character back into the input stream.
43) The condition inputFile >> word returns true until reaching the end of the input file.
44) The exit(1) function call in C++ indicates successful program termination.
45) The isspace() function returns true if the character is a space, tab, or newline.
46) The put() function is a member function of every input stream in C++.

47) Write a program using cin.get() to read a line of text, store it in a character array, and then print it back to the console. All characters, including spaces and special characters, should be read until the end of the line.
48) Modify the code in exercise 47 to read the line from a file and print it out to the console.
49) Write a program that counts the number of vowels in a given input file. The program should print out the line number and the position in the line where each vowel is found. This is a sample of the program output. The exact output depends on your input file contents.
ch07_exercise49

 

 

 

 

 

 

50) Write a program to generate random words and save them to a file. The program should allow users to enter how many words they wish to generate. The generated words must have random lengths ranging from 1 to a maximum of 8 characters long.

Projects

Project 01: Caesar Cipher

Write a program that encrypts and decrypts a text file’s contents using the Caesar Cipher. This ancient and simple algorithm works by replacing every letter with another letter selected after shifting forward a certain number of positions. The shift value can be any integer value. For example, if we choose the shift to be 5, then the word ‘hello’ will become ‘mjqqt’ following the normal English alphabet order. Similarly, to decipher this encrypted text, we must use the same shift value to move backward the same number of positions to retrieve the original text. This algorithm is based on the 26 English alphabet to cipher texts. Today, we can cipher all characters presented in the ASCII table. As every character in the ASCII table has an integer value, it is possible to shift this value to get a different character.

Develop a program that must meet the following requirements:

  1. Use the attached project skeleton to complete the project code.
  2. Check whether the input and output streams are initialized correctly.
  3. Write adequate preconditions and postconditions comments for all functions.
  4. Close streams appropriately.
  5. Use the attached imaginary input text file to test your project code.

Note that you MUST change the extension of the projectSkeleton.pdf file to a .cpp file, and the input_Text_Project01.pdf to a .txt file.

projectSkeleton.pdf
input_Text_Project01.pdf

 

Project 02 (not ready yet): Text Analyzer
– Count how many times every character occurs in the input text file.
– Draw a diagram of stars representing the numbers.
– Compare the most and the least used characters in the text.

 

License

Icon for the Creative Commons Attribution 4.0 International License

Introduction to C++ ( Volume I ) Copyright © 2025 by Hussam Ghunaim, Ph.D. is licensed under a Creative Commons Attribution 4.0 International License, except where otherwise noted.