2

I tried to format output strings in my console application (like a table)

cout <<  "\n\n-----------------\n";
cout << setw(8) << left << "F\t|";
cout << setw(8) << left << "x\t|";
cout <<  "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "\t|";

cout.width(8);
cout.setf(ios::left);
cout << x << "\t|";
cout <<  "\n-----------------\n\n";

But as result my output looks like this
enter image description here
What's wrong with my upper string formatting?

6
  • Are you asking why the line beginning with F isn't lining up with the other lines? Commented Aug 21, 2013 at 14:21
  • 6
    You forgot that numbers take up room? Commented Aug 21, 2013 at 14:21
  • @Andrew_CS yes, I'm asking about it. Commented Aug 21, 2013 at 14:23
  • Have you tried removing the tab? Commented Aug 21, 2013 at 14:23
  • 1
    If you are using setw, get rid of the \t's. Commented Aug 21, 2013 at 14:23

5 Answers 5

4

I used the same code as you did and got the same output until I removed the \t at the end of the line. See the new code:

cout <<  "\n\n-----------------\n";
cout << setw(8) << left << "F\t|";
cout << setw(8) << left << "x\t|";
cout <<  "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "|";

cout.width(8);
cout.setf(ios::left);
cout << x << "|";
cout <<  "\n-----------------\n\n";
Sign up to request clarification or add additional context in comments.

1 Comment

This. Since the output was already aligned to an 8-character boundary, the tab just pushed it an extra 8 characters out.
3

As already noted, it's the tabs that are causing the problem.

I would not stop at just removing the tabs though. As it stands right now, your code is highly repetitive and next to impossible to maintain. I'd do a (nearly) complete rewrite, with a couple of functions to cut down on the repetition. My first cut would probably look something like this:

// format a value in a field of specified width, followed by a separator
template <class T>
string field(T val, int w, char sep = '|') {
    stringstream b;
    b << setw(w) << left << fixed << setprecision(3) << val << sep;
    return b.str();
}

// generate a separator for a specified number of fields,
// each of a specified width
string sep(int c, int w, char val = '-') {
    string s(c * (w + 1), val);
    return string("\n") + s + "\n";
}

int main() {
    static const int w = 8;
    double F = 1.234, x = 3.45;
    string s = sep(2, w);

    cout << "\n" << s;
    cout << field("F", w) << field("x", w) << s;
    cout << field(F, w) << field(x, w) << s;
}

Seems to me that this makes the code rather more readable and quite a bit more maintainable. For example, if we decided to display an a and b on the next line, it would seem fairly obvious to add something like:

cout << field(a, w) << field(b, w) << s;

...and we wouldn't have to look very hard to be pretty sure it was going to match up with the previous line. Likewise, if we wanted to change a column width, etc.

7 Comments

+1, that's indeed absolutely proper way to go, but looking on such code I always thinking that there is something wrong trying to apply complicated solution on some really easy things... then something which is suppose to be really simple pretend to be a monster.. printf("| %8.3f | %8.3f |\n", f1, f2) up to me looks much more readable then c++ style formatting... this question about c++, i know i know i know.. but +1 anyway..
@evilruff: the fact that almost any output formatting library in any language uses format strings should be a hint that the operator<< way (implemented as currently is in C++) provides mostly an overcomplication of things that could be way simpler and easier to use.
@MatteoItalia I think in most of cases (again it's absolutely my personal opinion) operator<< is just misused. It's main purpose to 'transfer' an object to something else which is suitable to be 'stored' or 'put into' some sort of stream. It's like putting something in a box... but the way c++ deals with streams in sense of formatting by proposing to put something in stream which doing nothing but controls how something coming AFTER will be stored makes me fill that it's not right and lead to a lot of complicated and in most cases unneeded code...
@evilruff: the problem here is that the C++ library doesn't provide any better solution for "format string" formatting, so we are stuck with iostreams bizarre stream formatters and misuse of operator<<.
@MatteoItalia I know, but honestly I don't look on any language from 'religion' prospective point of view. Formatting from C could work pretty well inside C++ code not looking ugly then used properly. I tend to think that if something not fits then let's skip it =)
|
1

You may try:

cout <<  "\n\n-----------------\n";
cout << setw(8) << left << "F\t\t|";   // insert more tab here
cout << setw(8) << left << "x\t|";
cout <<  "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "\t|"; 

cout.width(8);
cout.setf(ios::left);
cout << x << "\t|";
cout <<  "\n-----------------\n\n";

Comments

1

The console screen looks suspiciously Windows like. If you are using Windows, you can use the Win32 API to format output more precisely. In particular, you can use SetConsoleCursorPosition.

COORD position = {x,y};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, position);
std::cout<<"This will be printed starting at position x, y"<<std::endl;

6 Comments

And what if the intent is to redirect output to a file?
@MarkRansom it should still be formatted fine. Windows just uses spaces for padding
@Cole"Cole9"Johnson: uhm, if the output has been redirected to file I think that GetStdHandle will return a file handle (and not a console screen buffer handle), so SetConsoleCursorPosition should just fail.
@Matteo I wouldn't know because I write cross platform code using the standard libraries, not the horrid Win32 API crap.
@Cole"Cole9"Johnson: then you should avoid writing misleading comments about the "horrid Win32 API crap"; besides, the situation is similar on *NIX systems: writing VT-100 escape sequences to position the cursor won't work with output redirected to file. The general (and reasonable) principle here is terminal cursor positioning commands don't work when writing to a text file, because a text file isn't a terminal.
|
1

Try this:

#include <iostream>
#include <iomanip>
#include <map>
#include <string>

using namespace std;


int main()
{
    map< float, float > table =
    {
        { 8232.0f, 89.0f },
        { 8232.1f, 89.0f },
        { 8232.2f, 89.0f },
        { 8232.3f, 89.0f },
        { 8232.4f, 89.0f },
        { 8232.5f, 89.0f },
        { 8232.6f, 89.0f },
        { 8232.7f, 89.0f },
        { 8232.8f, 89.0f },
    };

    const size_t CELL_WIDTH = 25;
    const string CELL_LINE( CELL_WIDTH, '=' );

    // print the header of table
    cout << '|' << CELL_LINE << '|' << CELL_LINE << '|' << endl
         << '|'
         << left << setw( CELL_WIDTH ) << "F" << '|'
         << setw( CELL_WIDTH ) << "R" << "|\n|"
         << CELL_LINE << '|' << CELL_LINE << '|' << endl;


    // print the body
    // change cout precision
    cout << fixed << setprecision( 3 );
    for ( auto it : table )
        cout << "| "  << setw( CELL_WIDTH - 1 ) << it.first
             << "| " << setw( CELL_WIDTH - 1 ) << it.second
             << "|\n";

    // print the footer
    cout << '|' << CELL_LINE << '|' << CELL_LINE << '|' << endl;


    return 0;
}

this is the result: enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.