How does std::setw work with string output?

AwaitedOne picture AwaitedOne · Feb 15, 2017 · Viewed 10.5k times · Source

I am trying to use set width setw for string output to an output file, however, I am not able to make it work. I have with me the following example.

// setw example
#include <iostream>     
#include <iomanip>      
#include <fstream>

int main () {
    std::ofstream output_file;
    output_file.open("file.txt");
    output_file << "first" <<std::setw(5)<< "second"<< std::endl;
    output_file.close();
  return 0;
}

Edit: With the above lines I expected to have many spaces between first and second, something like first second

I hardly see any spaces, the output just comes like firstsecond I think I missed the working of setw()

Note: For integers, it works fine just:

output_file << 1 <<std::setw(5)<< 2 << std::endl;

What I am doing wrong??.

Answer

WhozCraig picture WhozCraig · Feb 15, 2017

I suspect your understanding of std::setw is simply not correct. I think you need something more along the lines of a combination of:

What is happening in your code:

  • Uses std::setw(5) to establish a field width of five characters.
  • Sends "first" to the stream, which is five characters long, so the established field width is completely consumed. No additional filling takes place.
  • Sends "second" to the stream, which is six characters long, so again, the entire field width is consumed (and in-fact breached). Again, no filling takes place

If you're intent is to have something like this (with column numbers above to show positions):

 col: 0123456789012345678901234567890123456789
      first     second    third     fourth

Notice how each word starts on an even multiple of 10 boundary. One way to do that is by using :

  • A output position std::left (so the fill, if any goes on the right to achieve the desired width). This the default for strings, but it never hurts to be sure.
  • A fill character of std::setfill(' '). Again, the default.
  • A field width std::setw(10) Why such a large number? See below

Example

#include <iostream>
#include <iomanip>

int main ()
{
    std::cout << std::left << std::setfill(' ')
              << std::setw(10) << "first"
              << std::setw(10) << "second"
              << std::setw(10) << "third"
              << std::setw(10) << "fourth" << '\n';
    return 0;
}

Output (column numbers added)

0123456789012345678901234567890123456789
first     second    third     fourth

So what happens if we change the output location to std::right ? Well, with the identical program, changing only the first line to :

std::cout << std::right << std::setfill(' ')

we get

0123456789012345678901234567890123456789
     first    second     third    fourth

Finally, one constructive way of seeing where the fill characters are being applied is by simply changing the fill char to something visible (ie. something besides a space). The last two examples output, changing the fill char to std::setfill('*') produces the following output:

First

first*****second****third*****fourth****

Second

*****first****second*****third****fourth    

Notice in both cases, since none of the individual output items breached the std::setw value, the total output line size for each is the same. All that changed was where the fills were applied and the output aligned within the std::setw specification.