# 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 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++];

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


#### 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.

# Reference

Koenig, Andrew & Moo, Barbara E., Accelerated C++, Addison-Wesley, 2000

## One thought on “Accelerated C++ Solution to Exercise 5-8”

1. Martin says:

Johnny.

Good analysis. Your example input table is misleading. It looks like two blank lines should be entered after the ‘bbb’ for the first picture. When that is done, both vectors will have four elements and the test will pass.