first off you are not putting a width on the title or song number... this will cause problems since they push your collum over...
basically, you will always have this problem as long as you are no defining and enforcing the width for each column. The setw() manipulator sets the minimum width for a field, but it does not change the maximum, you have to do that yourself either by truncating strings that are too long or breaking the data into multiple rows.
Here is an example of formatting a table I posted a while back:
CODE
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
struct SomeData {
string aString;
long int anInt;
double aDouble;
};
string split(string &in, int length);
int main()
{
ostringstream oss(ostringstream::out);
//Ok first lest get some data...
SomeData data[5];
data[0].aString = "Hello World";
data[0].anInt = 11;
data[0].aDouble = 3.14159265;
data[1].aString = "To whome it may concern;";
data[1].anInt = 1123;
data[1].aDouble = 1.41421;
data[2].aString = "Laugh and the world laughs with you...";
data[2].anInt = 112358;
data[2].aDouble = 0.707107;
data[3].aString = "It was the best of times it was the worst of times...";
data[3].anInt = 1123581321;
data[3].aDouble = 1.61803399;
data[4].aString = "When, in the course of human events, it becomes necessary for one poeple to dissolve the political bounds...";
data[4].anInt = 1231853211;
data[4].aDouble = 1.94161104;
cout << setw(1) << "|" << setw(19) << "The String"
<< setw(1) << "|" << setw(19) << "The Integer"
<< setw(1) << "|" << setw(19) << "The Double"
<< setw(1) << "|" << endl;
cout << setfill('-') << setw(61) << "" << setfill(' ') << endl;
int counter = 0;
string rows[3];
while (counter < 5) {
//Convert each of the data portions to strings for manipulation
oss << data[counter].aString;
rows[0] = oss.str();
oss.str("");
oss << data[counter].anInt;
rows[1] = oss.str();
oss.str("");
oss << data[counter].aDouble;
rows[2] = oss.str();
oss.str("");
//Print out the data formatted to the table
while (rows[0] != "" || rows[1] != "" || rows[2] != "")
{
cout << setw(1) << "|" << setw(19) << left << split(rows[0], 20) << right
<< setw(1) << "|" << setw(19) << split(rows[1], 20)
<< setw(1) << "|" << setw(19) << split(rows[2], 20)
<< setw(1) << "|" << endl;
}
cout << setfill('-') << setw(61) << "" << setfill(' ') << endl;
counter++;
}
return 0;
}
//Split a string into two parts...
// return a part of at most "length"
// and remove from the original string.
string split(string &in, int length) {
string retString = "";
string temp;
if (in.length() > length) {
temp = in.substr(length - 1);
in.resize(length - 1);
retString = in;
in = temp;
} else
{
retString = in;
in = "";
}
return retString;
}
In this example the long strings are broken up onto multiple rows to keep the table structure. Note that I am controlling the width of each field I print.
The program also uses ostringstream to convert numbers into strings. This is convenient to tell how many character a numeric field will take.