Tidbits – Streams in C++

If you have watched Red with Bruce Willis you may recall the opening scene. Frank Moses (Bruce Willis) is a retired CIA operative and he is sleeping in his bed. On the night stand next to him there is a clock. The clock is ticking down to 06:00 AM. Just as the clock reaches 06:00 AM, without the need of an alarm, Frank Moses wakes up and calmly walks down to the kitchen to get breakfast. Obviously Frank Moses is a very disciplined and a morning person.

I am also a morning person. In general I wake up before 05:00 AM. As a fallback I have a 7-day alarm set in my phone for exactly 05:00 AM. Today I woke up and decided it was time to get up. Reached to my phone and it showed 04:59 AM. A second or two later the alarm went off. I just killed it and started my daily routine. As I was walking to the bathroom I smiled as I recalled the opening scene from Red.

For work, I am developing a reduced set of API calls in C++ for the storage server. I figured out that, given that streams are implemented in different ways and use slightly different syntax on different languages, that I would generate this post.

A stream is a sequence of bytes which can be finite or not. For example a stream used to read the contents of a file in disk is finite, while a stream reading the weather conditions (i.e., temperature, humidity, pressure) from a weather station constitutes an infinite stream. To read more about this topic you may look here.

In general we have iostream for input / output that handles cin, cout and cerr, fstream for files that handles ifstream and ofstream and stringstream for strings. Of course these are just the basic types of streams in C++.

Let’s start with writing a string to the output stream cout. We could have removed the ‘\n’ from the string and append a << endl. We could also have used a string and write the string. All three approaches are valid and seem to work well.

The next statements write one byte / character per call. Note how the exclamation points are written to the output stream one byte at a time.

Finally we write a greeting in two steps and flush the output stream. I am running this code on Windows 10. As you can see if you execute the code, the words appear as soon as they are written to the console. There is no need to flush the output stream.

	// **** writing to the cout I/O stream ****
	const string greeting = "Hello World!!!";

    cout << "Hello World!!!\n";
	cout << "Hello world!!!" << endl;
	cout << greeting << endl << endl;

	// **** writting to cout one byte / character at a time ****
	cout.put('J');
	cout.put('o');
	cout.put('h');
	cout.put('n');
	cout.put('!').put('!').put('!');
	cout.put('\n');
	cout << endl;

	// **** flusing the stream buffer ****
	cout << "Hello";
	Sleep(1000);
	
	cout << " John !!!\n";
	Sleep(1000);

	cout << flush;
	Sleep(1000);

We then prompt the user to enter their first name. We write the input stream to the firstName variable and then display it. As you should be able to tell only the first set of contiguous characters are read. Try experimenting by entering trailing spaces and perhaps the full name.

After the first name is extracted we clear the input stream. This is done to prevent reading left over characters that might have been entered by accident (e.g., user entered her full name).

The code the prompts for and reads the full name of the user which will be composed of multiple sets of continuous characters (e.g., James T. Kirk). The name is read as an entire line and displayed.

Finally we enter a loop prompting for full names which are read entirely per line.

	string firstName;

	// **** just read the first name, e.g., John Canessa ****
	cout << "please enter your first name: "; cin >> firstName;
	cout << "your name is ==>" << firstName << "<==\n";

	// **** clear cin (e.g., discard " Canessa" ****
	cin.ignore(INT_MAX, '\n');

	// **** reads the entire full name, e.g., John Canessa ****
	string fullName;

	cout << "please enter your full name: ";
	getline(cin, fullName);
	cout << "your full name is ==>" << fullName << "<==\n";

	// **** now in a loop ****
	for (int i = 0; i < 3; i++) {
		cout << "please enter your full name: ";
		getline(cin, fullName);
		cout << "your full name is ==>" << fullName << "<==\n";
	}

The next pass was an attempt to read one character at a time. This did not go well. I tried it on Linux and Windows. The code follows:

	// **** loop reading from cin one character at a time (ctrl-z to end) ****
	char c;

	cout << "please enter some text: "; cin >> c;
	cout << "\nblocked until \\n was entered\n";

	do {
		cout << c; cin >> c;
	} while (!cin.eof());
	cout << endl;

The results on Linux:

please enter some text: Hello World^Z
Hello World
all done !!!

And the results on Windows:

C:\Users\John\Documents\Visual Studio 2017\Projects\tidbits4\Debug>tidbits4
please enter some text: hello world^Z^Z

blocked until \n was entered
helloworld
^Z

Looked up what control-z does and it seems to return 0x1A. The logic of the code seems to work but it does not. The input stream is buffered until a ‘\n’ is found when the user presses the <Enter> key. The code follows:

	// **** now in C ****
	char c;
	printf("please enter some text: ");

	for (bool done = false; !done; ) {
		c = fgetc(stdin);
		if (c == 0x1A) {
			done = true;
			continue;
		}
		printf("%c", c);
	}

	printf("\nall done !!!\n");

Now we declare the Person class and illustrate how a method that converts the members to a string is implemented in two different ways. The idea is to show the string stream. Not sure if one approach is better than the other. I personally lean for the toString() method.

	// **** ****
	Person person = Person("John", "C", "Canessa", 21);
	cout << "person: " << person.toString() << endl;
	cout << endl;
	cout << "person: " << person.tostring() << endl;

The header for the Person class:

#pragma once

#include "pch.h"

using namespace std;

class Person
{

	// **** members ****
private:
	string	firstName;
	string	middleName;
	string	lastName;
	int		age;

public:
	// **** constructor ****
	Person(string firstName, string middleName, string lastName, int age);

	// **** destructor ****
	~Person();

	// **** to string ****
	string toString();

	// **** to string using sstream ****
	string tostring();
};

The implementation for the Person class:

#include "pch.h"
#include "Person.h"

using namespace std;

// **** constructor ****
Person::Person(string firstName, string middleName, string lastName, int age)
{
	this->firstName		= firstName;
	this->middleName	= middleName;
	this->lastName		= lastName;
	this->age			= age;
}

// **** destructor ****
Person::~Person()
{
}

// **** to string ****
string Person::toString()
{
	return firstName + " " + middleName + " " + lastName + " " + to_string(age);
}

// **** to string using a string stream ****
string Person::tostring()
{
	stringstream stm;
	stm << firstName << " " << middleName << " " << lastName << " " << age;
	return stm.str();
}

Finally we have some code that reads a set of grades from a file. The grades are read via a stream. The grades are then written to a string stream to be processed one by one. The loop reads a grade at a time and places it into the grade variable. The grade is used to update to total.

Once the loop ends, we compute the average grade and display the result:

	// **** values in file:  100 90 80 70 60  (all grades on a single line) ****

	const string	gradesFileName = "c:\\temp\\grades.txt";

	ifstream		gradeFile;

	stringstream	grades;

	int				grade,
					total = 0;

	// **** open the input file stream ****
	gradeFile.open(gradesFileName);

	// **** read the grades into line ****
	string line;
	getline(gradeFile, line);
	cout << "line ==>" << line << "<==" << endl;

	// **** close the input file stream ****
	gradeFile.close();

	// **** put the grades into the string stream ****
	grades << line; // **** process the grades **** int i; for (i = 0; true; ) { // **** check if the string stream is empty **** if (grades.rdbuf()->in_avail() == 0)
			break;

		// **** ****
		i++;

		// **** extract the next grade and process it ****
		grades >> grade;
		cout << "grade: " << grade << endl;
		total += grade;
	}
	cout << "i: " << i << endl;

	// **** compute and display the average ****
	double average;
	average = total / i;
	cout << "average: " << average << endl;

While I was writing this post I decided to load the Boots library into Visual Studio. Will get that completed for the next C++ post.

I pushed the code to my GitHub repository.

If you take a look at the code, you will see that different sections are bracketed by #ifdef _DEBUG and #endif. I use #ifdef CAKE to comment things out and _DBEUG to comment them back in.

If you have comments on this or any other post please leave me a note below.

Keep on learning;

John

Please follow me on Twitter:  @john_canessa

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.