Exercise 5-8
In the hcat function from S5.8.3/95, what would happen if we defined s outside the scope of the while? Rewrite and execute the program to confirm your hypothesis.
Solution
Note: the original hcat function may be found in my Solution to Exercise 5-0 (Part 3/3). The objective of this exercise is to understand what may happen should we vary the hcat function a little bit.
In short, defining the string s outside the while loop will cause problems for certain horizontal concatenation scenarios (this will explained shortly below). It is however ok to define that string s outside the while loop, as long as we also add a one-line statement inside the while loop (this will also be explained shortly below).
Potential Problem
This is what the hcat function looks like if we simply move the string s outside (or just before) the while loop.
Assuming we wish to use the hcat function to concatenate the following (left and right) vectors:
When the hcat function is invoked, the following tables summarise what happens:
Note that at the beginning of the second loop, because we did not re-initialise the string s, it causes the the s.size() to become larger than width1 (which is the maximum length of the longest string element within the left vector). This effectively results in negative string length when we apply the s += string(width1 – s.size(), ‘ ‘). The C++ implementation will likely bump into a string length error – highlighted in red.
Below shows what happens if we attempt to run this code as it is.
i.e. the program crashes as a result of negative string length. This can be fixed easily however – read on!
Resolution
To fix that string length error as described above, simply add a one-line statement within the while loop to re-initialise the string s at the beginning of each loop.
Again, assuming we wish to use the hcat function to concatenate the following (left and right) vectors:
When the hcat function is invoked, the following tables summarise what happens:
Below shows what happens if we attempt to run this corrected code – it should run smoothly as expected.
The Project
To wrap up the source and header files that I use to test my codes.
C++ Source File List
C++ Header File List
C++ Source Files
main.cpp
#include <iostream> // cin, cout, endl, getline #include <vector> // vector #include <string> // string #include "frame.h" // width, frame /*#include "vcat.h" // vcat */ #include "hcat.h" // hcat #include "vcout.h" // vcout using std::cin; using std::cout; using std::endl; using std::getline; using std::string; using std::vector; int main() { string line1; // line vector<string> para1; // paragraph cout << "define vector<string> para1 below..." << endl; // read multiple lines to make a paragraph while (getline(cin, line1)) para1.push_back(line1); cin.clear(); string line2; // line vector<string> para2; // paragraph cout << "define vector<string> para2 below..." << endl; // read multiple lines to make a paragraph while (getline(cin, line2)) para2.push_back(line2); cin.clear(); cout << "-----------------------------------------------------\n" "Display: hcat(para1, para2) \n" "-----------------------------------------------------\n"; vcout(hcat(para1, para2)); return 0; }
frame.cpp
#include <string> // string #include <vector> // vector #include <algorithm> // max using std::string; using std::vector; using std::max; string::size_type width(const vector<string>& v) { string::size_type maxlen = 0; for(vector<string>::size_type i = 0; i != v.size(); ++i) maxlen = max(maxlen, v[i].size()); return maxlen; } vector<string> frame(const vector<string>& v) { vector<string> ret; string::size_type maxlen = width(v); string border(maxlen + 4, '*'); // write the top border ret.push_back(border); // write each interior row, bordered by an asterisk and a space for (vector<string>::size_type i = 0; i != v.size(); ++i) ret.push_back("* " + v[i] + string(maxlen - v[i].size(), ' ') + " *"); // write the bottom border ret.push_back(border); return ret; }
hcat.cpp
#include <string> // string #include <vector> // vector #include "frame.h" // width using std::string; using std::vector; vector<string> hcat(const vector<string>& left, const vector<string>& right) { vector<string> ret; // add 1 to leave a space between pictures string::size_type width1 = width(left) + 1; // indices to look at elements from left and right respectively vector<string>::size_type i = 0, j = 0; string s; // continue until we've seen all rows from both pictures while (i != left.size() || j != right.size()) { // construct new string to hold characters from both pictures //string s; s = ""; // copy a row from the left-hand side, if there is one if (i != left.size()) s = left[i++]; // pad to full width s += string(width1 - s.size(), ' '); // copy a row from the right-hand side, if there is one if (j != right.size()) s += right[j++]; // add s to the picture we are creating ret.push_back(s); } return ret; }
vcout.cpp
#include <iostream> #include <string> // string #include <vector> // vector using std::cout; using std::endl; using std::string; using std::vector; int vcout(const vector<string>& v) { for (vector<string>::const_iterator iter = v.begin(); iter != v.end(); ++iter) { cout << (*iter) << endl; } return 0; }
C++ Header Files
frame.h
#ifndef GUARD_FRAME_H #define GUARD_FRAME_H #include <string> #include <vector> std::string::size_type width(const std::vector<std::string>&); std::vector<std::string> frame(const std::vector<std::string>&); #endif // GUARD_FRAME_H
hcat.h
#ifndef GUARD_HCAT_H #define GUARD_HCAT_H #include <string> #include <vector> std::vector<std::string> hcat(const std::vector<std::string>&, const std::vector<std::string>&); #endif // GUARD_HCAT_H
vcout.h
#ifndef GUARD_VCOUT_H #define GUARD_VCOUT_H #include <string> #include <vector> int vcout(const std::vector<std::string>&); #endif // GUARD_VCOUT_H
Conclusion
For the hcat function to work, we must re-initialise the string s at the beginning of each loop, as illustrated above.