Closed 0oWillo0 closed 9 years ago
这个代码的注释非常清楚。
仅看输出就清楚了。
// print results for the previous book std::cout << total << std::endl;
这句输出,是在 total.isbn() != trans.isbn()
发生的。即,在你输入了
a 1 2
之后,再输入
b 1 2
的时候, b != a
,程序走到这一个输出语句,然后就会输出 a.
因为程序的逻辑是,当你输入了另一个商品 b 的时候,默认你是完成了商品 a 的输入的,于是输出 a 的总价。但此刻,商品 b 仍处于未完成的状态,你有可能接下来还要输入商品 b 的另一条单价,也有可能输入商品 c,只有当你输入另一个商品 c 的时候,才会认为商品 b 已经输入完成,才会输出 b 的总价。
所以此刻仅仅会输出商品 a 。
std::cout << total << std::endl; // print the last transaction
这是第二处输出,是当你结束 while
循环的时候输出的,何时结束?在 Windows 操作系统上就是按 Ctrl
+ Z
键结束输入。那么当你按下这两个键的时候,程序会将最后一个商品,如此刻的商品 b,置为完成状态,然后输出出来。
所以当你输入完 b,紧接着会输出 a,然后你按下 Ctrl
+ Z
,会输出 b。
这就是整个程序逻辑的分析,相信你该明白为何 a 和 b 不会一起输出出来了吧。
那么如果你非要在输入商品 b 的时候,将此刻完成状态的商品 a 和未完成状态的商品 b 都输出出来。 请修改代码:
else { // print results for the previous book std::cout << total << std::endl; // 这里加入一句话 std::cout << trans << std::endl; total = trans; // total now refers to the next book }
当然,这样的话,输出信息就和程序本身的逻辑有点不协调了。但满足了你的需求。
#include <iostream>
int main()
{
// currVal is the number we're counting; we'll read new values into val
int currVal = 0, val = 0;
// read first number and ensure that we have data to process
if (std::cin >> currVal) {
int cnt = 1; // store the count for the current value we're processing
while (std::cin >> val) { // read the remaining numbers
if (val == currVal) // if the values are the same
++cnt; // add 1 to cnt
else { // otherwise, print the count for the previous value
std::cout << currVal << " occurs "
<< cnt << " times" << std::endl;
currVal = val; // remember the new value
cnt = 1; // reset the counter
}
} // while loop ends here
// remember to print the count for the last value in the file
std::cout << currVal << " occurs "
<< cnt << " times" << std::endl;
} // outermost if statement ends here
return 0;
}
这个程序在1 1 2 2 2 最后加个ctrl+z然后再回车可以一起输出,但是为什么上面那个不行啊?不应该也是最后一个^Z然后相当于输入结束然后把前一个打印出来吗?
@0oWillo0
这个程序在1 1 2 2 2 最后加个ctrl+z然后再回车可以一起输出,但是为什么上面那个不行啊?
按照你对上面那个程序的输入:
a 1 2 b 1 2 Ctrl+Z
我们来分析发生了什么。
if (std::cin >> total)
首先这句里面的 std::cin >> total
,你要了解背后是什么。这一点是与你写的那个程序最大的不同。 total
是一个 Sales_item
对象,它恰好又重载了 operator>>
操作符。我将这句话展开一下:
std::istream&
operator>>(std::istream& in, Sales_item& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price; // 真正的输入在这里
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_item(); // input failed: reset object to default state
return in;
}
好,if
那一句读入 a 1 2
,没问题,接下来重点分析 while
那一句:
while (std::cin >> trans)
第一次执行 while,正常读入 b 1 2
,没问题吧。此刻输出了 a,然后第二次读入你最后加的那个 Ctrl
+Z
,即 EOF
。它实际执行的是哪一句呢?
in >> s.bookNo >> s.units_sold >> price;
^
EOF 跑到 s.bookNo 的位置
EOF
本质就是个枚举值,你可以把它看作是一个bit
,不同编译器是不同的值,譬如在 VS2013 里,它被定义为 0x1
。那么由于 bookNo
是一个 std::string
,那么 std::ios_base
在处理这个 bit
的时候,就默认将其作为 std::string
来处理,什么结果呢?有兴趣你可以 debug 跟踪这个过程,大体来讲,最终处理成了空字符串(""),且 ios_base::iostate
的值依然是 good
。即什么也没有。但输入流并未结束啊!还等着输入 units_sold
呢。这是一个 unsigned
类型,它遇到 eofbit
不会处理的如 std::string
那么复杂,依然可以跟踪一下,最终 ios_base::iostate
的值会是 eofbit
,即输入流结束,后续的 if
判断会 false
,然后构造一个空的 Sales_item
对象。
说了这么多,其实就是 std::string
惹的货。
我稍微改动一下你最后那个“行为正常”的代码:
#include <iostream>
#include <string>
int main()
{
// currVal is the number we're counting; we'll read new values into val
std::string currName, name;
int currVal = 0, val = 0;
// read first number and ensure that we have data to process
if (std::cin >> currName >> currVal) {
int cnt = 1; // store the count for the current value we're processing
while (std::cin >> name >> val) { // read the remaining numbers
if (val == currVal) // if the values are the same
++cnt; // add 1 to cnt
else { // otherwise, print the count for the previous value
std::cout << currVal << "(" << currName << ")" << " occurs "
<< cnt << " times" << std::endl;
currVal = val; // remember the new value
currName = name;
cnt = 1; // reset the counter
}
} // while loop ends here
// remember to print the count for the last value in the file
std::cout << currVal << "(" << currName << ")" << " occurs "
<< cnt << " times" << std::endl;
} // outermost if statement ends here
return 0;
}
然后按照你的顺序输入:
a 1 a 1 b 2 b 2 b 2 Ctrl+Z
会是什么结果呢?
仅仅只会输出
1(a) occurs 2 times
然后等待输入。和书上的程序保持了一致。
理解了?
不应该也是最后一个^Z然后相当于输入结束然后把前一个打印出来吗?
想做到你这一点,有两个办法:
Sales_item
类里面的 bookNo
作为第一个输入。a 1 2 b 1 2 b Ctrl+Z
(注意 Ctrl+Z 前面那个字符,随便给个即可,主要是为了让 bookNo
正常读进去)都可以做到你想要的结果。
这是答案,然后我运行时输入a 1 2 b 1 2结果只会显示出a商品的情况,b无法显示。我试了ctrl+z也是不行。现在不知道要怎么搞才能让ab商品一起输出,希望大神能帮忙解决下这个疑惑。