void graph::fillTable()
{
ifstream fin;
char X;
int slot=0;
fin.open("data.txt");
while(fin.good()){
fin>>Gtable[slot].Name;
fin>>Gtable[slot].Out;
cout<<Gtable[slot].Name<<endl;
for(int i=0; i<=Gtable[slot].Out-1;i++)
{
**//cant get here**
fin>>X;
cout<<X<<endl;
Gtable[slot].AdjacentOnes.addFront(X);
}
slot++;
}
fin.close();
}
那是我的代码,基本上它完全符合我的要求,但当文件不再有效时它会继续读取。它会输入和输出我要查找的所有内容,然后当文件结束时,fin.good() 显然不会返回 false。这是文本文件。
A 2 B F
B 2 C G
C 1 H
H 2 G I
I 3 A G E
F 2 I E
这是输出
A
B
F
B
C
G
C
H
H
G
I
I
A
G
E
F
I
E
Segmentation fault
-
这是 Gtable 的类型。
struct Gvertex:public slist
{
char Name;
int VisitNum;
int Out;
slist AdjacentOnes;
//linked list from slist
};
我希望它在输出“E”(文件中的最后一个字符)后停止。读取最后一个字符后,程序再也不会进入 for 循环。我不明白为什么 while 没有中断。
最佳答案
您在 while 循环中的条件是错误的。 ios::eof()
不是
有预见性的;只有在流尝试过后才会设置
(内部)读取超出文件末尾的内容。你必须在每次检查后检查
输入。
处理您的案例的经典方法是定义一个 >>>
GTable
的函数,按照以下行:
std::istream&
operator>>( std::istream& source, GTable& dest )
{
std::string line;
while ( std::getline( source, line ) && line.empty() ) {
}
if ( source ) {
std::istringstream tmp( line );
std::string name;
int count;
if ( !(tmp >> name >> count) ) {
source.setstate( std::ios::failbit );
} else {
std::vector< char > adjactentOnes;
char ch;
while ( tmp >> ch ) {
adjactentOnes.push_back( ch );
}
if ( !tmp.eof() || adjactentOnes.size() != count ) {
source.setstate( std::ios::failbit );
} else {
dest.Name = name;
dest.Out = count;
for ( int i = 0; i < count; ++ i ) {
dest.AdjacentOnes.addFront( adjactentOnes[ i ] );
}
}
}
}
return source;
}
(这写得相当仓促。在实际代码中,我几乎可以肯定 将内部循环分解为一个单独的函数。)
注意:
我们逐行读取,以验证格式(并允许 出现错误时重新同步)。
我们在源流中设置了
failbit
以防输入错误。我们跳过空行(因为您的输入显然包含它们)。
我们不会修改目标元素,直到我们确定输入 是正确的。
我们有这个,很容易遍历所有元素:
int slot = 0;
while ( slot < GTable.size() && fin >> GTable[ slot ] ) {
++ slot;
}
if ( slot != GTable.size )
// ... error ...
编辑:
我会明确指出这一点,因为其他人的回应似乎 错过它:绝对有必要确保你有 在尝试阅读之前阅读的地方。
编辑 2:
考虑到这个问题收到的错误答案的数量,我会 喜欢强调:
fin.eof()
之前已知输入失败的任何使用都是错误的。fin.good()
的任何使用都是错误的。在测试输入之前使用读取的值之一 已经成功是错误的。 (这不会阻止像
fin >> a >> 这样的事情 b
,只要既不使用a
也不使用b
才成功 测试。)任何试图读入
Gtable[slot]
而未确保slot
在边界内是错误的。
关于 eof()
和 good()
:
istream
和ostream
的基类定义了三个
“错误”位:failbit
、badbit
和 eofbit
。它是
理解这些设置的时间很重要:badbit
是在
不可恢复的硬件错误(实际上从来没有,因为大多数
实现不能或不会检测到此类错误);并且 failbit
设置在
输入失败的任何其他情况——要么没有可用数据(结束
文件)或格式错误("abc"
输入 int 等)。
eofbit
设置任何时候 streambuf
返回EOF
,这是否
导致输入失败与否!因此,如果您读取一个 int
,并且
流包含 "123"
,没有尾随空格或换行符,
eofbit
将被设置(因为流必须提前读取才能知道在哪里
int
结束);如果流包含"123\n"
,则不会设置eofbit
。
然而,在这两种情况下,输入都会成功,并且 failbit
不会
设置。
要读取这些位,有以下函数(作为代码,因为我 否则不知道如何获得一张 table ):
eof(): returns eofbit
bad(): returns badbit
fail(): returns failbit || badbit
good(): returns !failbit && !badbit && !eofbit
operator!(): returns fail()
operator void*(): returns fail() ? NULL : this
(typically---all that's guaranteed is that !fail() returns non-null.)
鉴于此:第一个检查必须始终是 fail()
或其中一个
operator
(基于fail
)。一旦 fail()
返回 true,我们
可以使用其他函数来确定原因:
if ( fin.bad() ) {
// Serious problem, disk read error or such.
} else if ( fin.eof() ) {
// End of file: there was no data there to read.
} else {
// Formatting error: something like "abc" for an int
}
实际上,任何其他使用都是错误的(任何使用 good()
是一个错误——别问我为什么有这个函数)。
关于c++ - 读取文件时找到文件末尾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8241792/