C++ 此代码旨在输出 Hello World。但它输出 0x22fed8
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/551082/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
This code is meant to output Hello World. but it outputs 0x22fed8
提问by WoW
I'm learning File Handling in C++, but there is a problem here. I am trying to read a file. This code is meant to output Hello World. but it outputs 0x22fed8.
我正在学习 C++ 中的文件处理,但这里有一个问题。我正在尝试读取文件。此代码旨在输出 Hello World。但它输出 0x22fed8。
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
fstream file;
file.open("test.txt",ios::in|ios::out);
file << "Hello World";
cout << file;
file.close();
return 0;
}
What am I doing wrong?
我究竟做错了什么?
回答by Konrad Rudolph
Simple solution
简单的解决方案
As others have pointed out, directly printing a file to a stream does't work. Printing the file contents would require opening another streamthat reads from the file, or re-setting your stream's read pointer to the beginning and then reading the whole file again (as others have shown).
正如其他人指出的那样,直接将文件打印到流是行不通的。打印文件内容需要打开另一个从文件中读取的流,或者将流的读取指针重新设置为开头,然后再次读取整个文件(如其他人所示)。
C++ doesn't do this automatically but you can do it manually (here, opening a new stream):
C++ 不会自动执行此操作,但您可以手动执行此操作(此处,打开一个新流):
ifstream ifs("filename");
Now, writing the file contents to another stream is a trivial addition. Instead of writing the file, simply write the file buffer:
现在,将文件内容写入另一个流是一个微不足道的补充。无需写入文件,只需写入文件缓冲区:
cout << ifs.rdbuf() << endl;
That's all! No loop needed to read the file line by line.
就这样!不需要循环来逐行读取文件。
Testing for valid streams
测试有效的流
While we're on the subject of loops, beware of code that reads files in a loop in the following manner:
当我们讨论循环时,请注意以下列方式在循环中读取文件的代码:
while ( !file.eof() )
This code produces an endless loop when there's a reading error. This an happen in many, many situations. Consider e.g. that the file is deleted while you read it, or that someone removes the USB device containing the file or that the file is wrongly formatted. All these cases would create an infinity loop here. Neveronly test for eof
in a stream.
当出现读取错误时,此代码会产生无限循环。这在很多很多情况下都会发生。考虑例如文件在您阅读时被删除,或者有人移除了包含该文件的 USB 设备,或者文件格式错误。所有这些情况都会在这里创建一个无限循环。永远不要只eof
在流中测试。
Luckily, the solution to this problem is also quite simple. Furthermore, it explains why your original code yielded such a weird result. In fact, streams in C++ have an implicit conversion to a bool
-liketype. For reasons explained elsewhere (cue: safe bool idiom), it is actually converted to void*
.
幸运的是,这个问题的解决方案也很简单。此外,它还解释了为什么您的原始代码会产生如此奇怪的结果。事实上,流在C ++中具有的隐式转换的bool
样式。由于其他地方解释的原因(提示:safe bool idiom),它实际上被转换为void*
.
This makes it easy to test whether a stream is in a valid, not-at-end state and can safely be read from. Therefore, we can reformulate the loop appropriately:
这使得测试流是否处于有效、非结束状态以及是否可以安全读取变得容易。因此,我们可以适当地重新构造循环:
while (file) …
The above code relies on the conversion to void*
taking place. Any nonnull
pointer indicates a valid stream. Now, the same happens in your code:
上面的代码依赖于发生的转换void*
。任何非null
指针都表示一个有效的流。现在,同样的情况发生在您的代码中:
cout << file;
Since there's no appropriate overload for operator <<
that takes a stream, C++ looks for other overloads and finds an overload for pointers. So it implicitly calls something like this:
由于没有合适的重载来operator <<
获取流,C++ 会寻找其他重载并找到指针的重载。所以它隐含地调用了这样的东西:
cout << static_cast<void*>(file);
Better solution
更好的解决方案
I've explained a simple, working solution above. However, this solution requires re-opening the file and reading it to memory again. This doubles the work required. We can make this better by introducing a new class that acts like a stream and that actually sends each output to two streams at once. This way, you can write your data both to the file and to the standard stream at the same time. No need to re-read the file.
我在上面解释了一个简单的、有效的解决方案。但是,此解决方案需要重新打开文件并再次将其读入内存。这使所需的工作增加了一倍。我们可以通过引入一个新类来改善这一点,该类的作用类似于流,并且实际上将每个输出一次发送到两个流。这样,您可以同时将数据写入文件和标准流。无需重新读取文件。
The class in itself is quite simple. The following complete code demonstrates the general principle:
这个类本身非常简单。以下完整代码演示了一般原理:
#include <iostream>
#include <fstream>
struct sinkpair {
sinkpair(std::ostream& a, std::ostream& b) : a(a), b(b) { }
// Forward all ouputs to both streams.
template <typename T>
sinkpair& operator <<(T const& value) {
a << value;
b << value;
return *this;
}
// Explicit overload needed for manipulators such as `endl`.
sinkpair& operator <<(std::ostream& (*manip)(std::ostream&)) {
a << manip;
b << manip;
return *this;
}
private:
std::ostream& a;
std::ostream& b;
};
int main() {
std::ofstream ofs("test.txt");
sinkpair sp(std::cout, ofs);
sp << "Hello" << std::endl;
}
回答by Andrei Taranchenko
EDIT:With mrree's suggestions.
编辑:根据mrree的建议。
ifstream fin("file.txt");
if (fin.is_open() == false) {
// error
}
string line;
while( getline(fin, line) ) {
cout << line;
}
回答by JaredPar
Lets examine the line
让我们检查一下这条线
cout << file;
The reason this outputs a number is because deep under the hood fstream is a file pointer. By passing file to cout you're essentially asking for a cout of an fstream. This will default to the value of the underlying handle for the file.
之所以输出一个数字,是因为在 fstream 的深处是一个文件指针。通过将文件传递给 cout,您实际上是在请求 fstream 的 cout。这将默认为文件的基础句柄的值。
If you want to output the contents of the file, you'll need to read it in and output it line by line.
如果要输出文件的内容,则需要将其读入并逐行输出。
fstream file;
file.open("test.txt",ios::in|ios::out);
file << "Hello World";
file.seekg (0, ios::beg);
while ( !file.eof() ) {
string temp;
file >> temp;
cout << temp << std::eol;
}
file.close();
回答by Thomas L Holaday
#include <iostream>
#include <fstream>
int main(int, char **)
{
std::ifstream input("test.txt");
char c;
while (input >> c) {
std::cout << c;
}
return 0;
}
Don't include the whole standard namespace. If you want an input file stream, use an ifstream.
不要包含整个标准命名空间。如果需要输入文件流,请使用 ifstream。
You want to output the contents of the file, not the file.
您想输出文件的内容,而不是文件。
If you want to write to a file, then read it back and send it to stdout,
如果要写入文件,则将其读回并将其发送到标准输出,
#include <iostream>
#include <fstream>
int main(int, char **)
{
std::fstream file("test.txt",std::ios::in|std::ios::out);
file << "Hello" << std::endl;
file.seekp(std::ios::beg);
char c;
while (file >>c) {
std::cout << c ;
}
return 0;
}
Konrad has the best answer, but consider the high-level approach:
康拉德有最好的答案,但请考虑高级方法:
#include <algorithm>
#include <iostream>
#include <fstream>
#include <iterator>
int main(int, char **)
{
std::fstream file("test.txt",std::ios::in|std::ios::out);
file << "Hello" << std::endl;
file.seekp(std::ios::beg);
std::copy(
std::istream_iterator<char>(file),
std::istream_iterator<char>(),
std::ostream_iterator<char>(std::cout)
);
return 0;
}