c++输出格式,转载

重点说明,本文转载,只做学习使用,不做商业用途,如有不妥请联系删除

Output Formatting
Many students complain that C++ streams are difficult to use for output, when compared to the older C methods. My theory is that, if the situation were reversed and students were required to move from C++ stream formatting back to the old methods, the complaints would be louder.

The biggest single advantage to the stream methods is they are type-safe. If you change a variable’s type, the subsequent stream operations using that variable will either automatically accommodate the change, or will indicate an incompatibility at compile time. In older C code, any number of difficult-to-detect bugs result from either incorrectly specifying a variable’s type, or changing the variable’s type and not remembering all the places where the specifiers need to be changed.

Please remember — this is a very basic introduction. Like this entire tutorial, this page is not a comprehensive guide to stream formatting — it just answers the most commonly heard student questions. A quality textbook should be acquired to serve more general needs.

  1. Field Width

Setting field width is very simple. For each variable, simply precede it with “setw(n)”. Like this:

include

include

using namespace std;

int main()
{
const int max = 12;
const int width = 6;
for(int row = 1;row <= max;row++) {
for(int col = 1;col <= max;col++) {
cout << setw(width) << row * col;
}
cout << endl;
}
return 0;
}

Notice how “setw(n)” controls the field width, so each number is printed inside a field that stays the same width regardless of the width of the number itself.

  1. Justification in Field

Now that you have selected a field, you may wish to decide which side of this field to occupy. As you may imagine, the choices are left and right. Here is an example of switching justification line-by-line:

include

include

using namespace std;

int main()
{
const int max = 12;
const int width = 6;
for(int row = 1;row <= max;row++) {
if(row % 2) {
cout << setiosflags(ios::left);
}
else {
cout << resetiosflags(ios::left);
}
for(int col = 1;col <= max;col++) {
cout << setw(width) << row * col;
}
cout << endl;
}
return 0;
}

Because numbers are by default right-justified, in this case I only need to set and unset the “ios::left” flag. In other situations, you may want to use “ios::right” in code similar to this.

Unfortunately, there are two flags, “ios::left” and “ios::right”. This leads to an obvious confusion about which flag is active. In some ambiguous cases, you may have to do this:

cout << setiosflags(ios::right);
cout << resetiosflags(ios::left);
  1. Controlling Precision

“Precision” in this context means the number of decimal places in a floating-point variable. Compile and run the following program:

include

include

using namespace std;

int main()
{
double x = 800000.0/81.0;
cout << setprecision(2) << x;
return 0;
}

This program isn’t broken — you asked for two places, it printed two places. If instead you want two decimal places (positions to the right of the decimal point), you must first choose the fixed-point format. Like this:

include

include

using namespace std;

int main()
{
double x = 800000.0/81.0;
cout << setiosflags(ios::fixed) << setprecision(2) << x;
return 0;
}

This is a very common student problem — the default C++ stream behavior for setprecision(n) is to apply the specification to the entire number, not the fractional part. If this is not what you want, set the fixed-point format first.

There is something very important to know about “setprecision(n)”. If you choose a precision this way, the displayed number will be rounded off appropriately. Experiment with the following program:

include

include

using namespace std;

int main()
{
double x = 2.0/3.0;
cout << setiosflags(ios::fixed) << setprecision(4) << x;
return 0;
}

The result (.6667) is an appropriate four-digit representation of the repeating decimal fraction 2/3. If you do not want this behavior, you will need to think of a different method for display. In most cases, the default behavior is the correct one.

  1. Leading zeros

The C++ stream classes provide an easy way to choose a character to fill the leading spaces in a number (and this program has a deliberate bug):

include

include

using namespace std;

void showDate(int m, int d, int y)
{
cout << setfill(‘0’);
// this line has an error
cout << setw(2) << m << ‘/’ << d << ‘/’ << y << endl;
}

int main()
{
showDate(1,1,1999);
return 0;
}

The bug (no leading character in the month) is caused by the fact that “setw(n)” is volatile. “setw(n)” only works for a single subsequent variable. You must apply “setw(n)” for each variable. Do it this way:

include

include

using namespace std;

void showDate(int m, int d, int y)
{
cout << setfill(‘0’);
cout << setw(2) << m << ‘/’
<< setw(2) << d << ‘/’
<< setw(4) << y << endl;
}

int main()
{
showDate(1,1,1999);
return 0;
}

  1. Number Bases other than 10

For base 8 and base 16, this is an easy problem to solve:

include

using namespace std;

int main()
{
unsigned long x = 64206;
cout << x
<< ” in base 8 is \”” << oct << x << “\””
<< ” and in base 16 is \”” << hex << x << “\”” << endl;
return 0;
}

By the way, this stream formatting for different bases also works for input:

int x;
cin >> hex >> x;

There is no general arbitrary-base display solution built into the language. Here is an example of a solution:

include

include

using namespace std;

string convBase(unsigned long v, long base)
{
string digits = “0123456789abcdef”;
string result;
if((base < 2) || (base > 16)) {
result = “Error: base out of range.”;
}
else {
do {
result = digits[v % base] + result;
v /= base;
}
while(v);
}
return result;
}

int main()
{
unsigned long x = 64206;
cout << “Hex: ” << convBase(x,16) << endl;
cout << “Decimal: ” << convBase(x,10) << endl;
cout << “Octal: ” << convBase(x,8) << endl;
cout << “Binary: ” << convBase(x,2) << endl;
cout << “Test: ” << convBase(x,32) << endl;
return 0;
}

  1. Currency

This is an advanced topic, because displaying currency is more complex than it may appear at first sight. There is an advanced C++ feature called “locale” that can handle this problem in a powerful way, but it is not enabled on many compilers (and not yet on the very common compiler I have chosen for this tutorial). Here is a way to display currency:

include

include

include

using namespace std;

void showCurrency(double dv, int width = 14)
{
const string radix = “.”;
const string thousands = “,”;
const string unit = “$”;
unsigned long v = (unsigned long) ((dv * 100.0) + .5);
string fmt,digit;
int i = -2;
do {
if(i == 0) {
fmt = radix + fmt;
}
if((i > 0) && (!(i % 3))) {
fmt = thousands + fmt;
}
digit = (v % 10) + ‘0’;
fmt = digit + fmt;
v /= 10;
i++;
}
while((v) || (i < 1));
cout << unit << setw(width) << fmt.c_str() << endl;
}

int main()
{
double x = 12345678.90;
while(x > .001) {
showCurrency(x);
x /= 10.0;
}
return 0;
}

This approach has many drawbacks. I have converted the double to an unsigned long before beginning my algorithm, which limits the range of possible currency amounts. Try experimenting with this code — test the various statements to see how they work. And if you are ambitious, see if you can make a double work directly, without converting to an unsigned long first (and good luck :) ).

Also notice the width argument to “showCurrency()”. Notice it is given a default value, which makes it unnecessary to even specify a value when the function is called. This default argument syntax is a standard feature of C++. If you want a width other than 14, you may include your own value in your call to the function. Like this:

    showCurrency(x, 16);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值