读取文件时查找文件结尾
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 没有中断。
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();
}
That's my code, basically it does exactly what I want it to but it keeps reading when the file is not good anymore. It'll input and output all the things I'm looking for, and then when the file is at an end, fin.good() apparently isn't returning false. Here is the text file.
A 2 B F
B 2 C G
C 1 H
H 2 G I
I 3 A G E
F 2 I E
and here is the output
A
B
F
B
C
G
C
H
H
G
I
I
A
G
E
F
I
E
Segmentation fault
-
Here's is Gtable's type.
struct Gvertex:public slist
{
char Name;
int VisitNum;
int Out;
slist AdjacentOnes;
//linked list from slist
};
I'm expecting it to stop after outputting 'E' which is the last char in the file. The program never gets into the for loop again after reading the last char. I can't figure out why the while isn't breaking.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
你在 while 循环中的条件是错误的。
ios::eof()
不是预测性;仅当流尝试后才会设置
(内部)读取超出文件末尾的内容。您必须在每次之后检查
输入。
处理案例的经典方法是定义一个
>>
GTable
的函数,大致如下:(这是相当仓促地编写的。在实际代码中,我几乎可以肯定
将内部循环分解为一个单独的函数。)
请注意:
我们逐行读取,以验证格式(并允许
发生错误时重新同步)。
我们在源流中设置
failbit
,以防出现输入错误。我们跳过空行(因为您的输入显然包含它们)。
在确定输入内容之前,我们不会修改目标元素
是正确的。
我们有这个,很容易循环所有元素:
编辑:
我会明确指出这一点,因为其他人的回应似乎
错过它:绝对有必要确保您已经
在尝试读取之前读取的位置。
编辑2:
考虑到这个问题收到的错误答案数量,我会
需要强调的是:
在已知输入失败之前使用
fin.eof()
都是错误的。任何使用
fin.good()
(句点)的行为都是错误的。在测试输入之前读取的值之一的任何使用
已经成功了是错误的。 (这并不能阻止诸如
fin >> a >> 之类的事情
,只要b
a
和b
都不使用就成功已测试。)
在不确保
slot
的情况下尝试读入Gtable[slot]
在边界内是错误的。
关于
eof()
和good()
:istream
和ostream
的基类定义了三个“错误”位:
failbit
、badbit
和eofbit
。它是理解这些设置的时间很重要:
badbit
是在以下情况下设置的:不可恢复的硬件错误(实际上从来没有,因为大多数
实现不能或没有检测到此类错误);并且
failbit
设置为在任何其他情况下,输入失败 - 要么没有可用数据(结束
文件),或格式错误(输入 int 等时的
"abc"
)。eofbit
被设置 任何时候,streambuf
返回EOF
,无论这导致输入失败与否!因此,如果您读取
int
,并且流包含
"123"
,没有尾随空格或换行符,eofbit
将被设置(因为流必须提前读取以了解int
结束);如果流包含“123\n”
,则不会设置eofbit
。然而,在这两种情况下,输入都会成功,并且
failbit
不会被放。
要读取这些位,有以下函数(作为代码,因为我
否则不知道如何获取表格):
鉴于此:第一个检查必须始终是
fail()
或其中之一operator
(基于fail
)。一旦fail()
返回 true,我们可以使用其他函数来确定原因:
实际上,任何其他使用都是错误(以及任何使用
good()
是一个错误——不要问我为什么有这个函数)。
Your condition in the while loop is wrong.
ios::eof()
isn'tpredictive; it will only be set once the stream has attempted
(internally) to read beyond end of file. You have to check after each
input.
The classical way of handling your case would be to define a
>>
function for
GTable
, along the lines of:(This was written rather hastily. In real code, I'd almost certainly
factor the inner loop out into a separate function.)
Note that:
We read line by line, in order to verify the format (and to allow
resynchronization in case of error).
We set
failbit
in the source stream in case of an input error.We skip empty lines (since your input apparently contains them).
We do not modify the target element until we are sure that the input
is correct.
One we have this, it is easy to loop over all of the elements:
EDIT:
I'll point this out explicitly, because the other people responding seem
to have missed it: it is absolutely imperative to ensure that you have
the place to read into before attempting the read.
EDIT 2:
Given the number of wrong answers this question is receiving, I would
like to stress:
Any use of
fin.eof()
before the input is known to fail is wrong.Any use of
fin.good()
, period, is wrong.Any use of one of the values read before having tested that the input
has succeeded is wrong. (This doesn't prevent things like
fin >> a >>
, as long as neitherb
a
orb
are used before the success istested.)
Any attempt to read into
Gtable[slot]
without ensuring thatslot
is in bounds is wrong.
With regards to
eof()
andgood()
:The base class of
istream
andostream
defines three“error” bits:
failbit
,badbit
andeofbit
. It'simportant to understand when these are set:
badbit
is set in case of anon-recoverable hardward error (practically never, in fact, since most
implementations can't or don't detect such errors); and
failbit
is set inany other case the input fails—either no data available (end of
file), or a format error (
"abc"
when inputting an int, etc.).eofbit
is set anytime thestreambuf
returnsEOF
, whether thiscauses the input to fail or not! Thus, if you read an
int
, and thestream contains
"123"
, without trailing white space or newline,eofbit
will be set (since the stream must read ahead to know where theint
ends); if the stream contains"123\n"
,eofbit
will not be set.In both cases, however, the input succeeds, and
failbit
will not beset.
To read these bits, there are the following functions (as code, since I
don't know how to get a table otherwise):
Given this: the first check must always be
fail()
or one of theoperator
(which are based onfail
). Oncefail()
returns true, wecan use the other functions to determine why:
Practically speaking, any other use is an error (and any use of
good()
is an error—don't ask me why the function is there).
稍慢但更干净的方法:
如果您仍然遇到问题,则与文件读取无关......
Slightly slower but cleaner approach:
If you still have issues, it's not with file reading...
在您实际从文件末尾读取之前,文件不会失败。直到
fin>>Gtable[slot].Name;
行才会发生这种情况。由于您的检查是在此之前,所以 good 仍然可以返回 true。一种解决方案是添加额外的失败检查,如果失败则跳出循环。
这仍然不能很好地处理输入文件中的格式错误;为此,您应该像其他一些答案中提到的那样逐行阅读。
The file won't fail until you actually read from past the end of file. This won't occur until the
fin>>Gtable[slot].Name;
line. Since your check is before this, good can still return true.One solution would be to add additional checks for failure and break out of the loop if so.
This still does not handle formatting errors in the input file very nicely; for that you should be reading line by line as mentioned in some of the other answers.
尝试在 while 条件下移动前两个读取:
编辑:根据 James Kanze 的评论,您将地址置于 Gtable 数组末尾之后,这就是导致段错误的原因。您可以将
Gtable
的大小作为参数传递给 fillTable() 函数(例如void fillTable(int table_size)
)并检查slot
在每次读取之前都在边界内。Try moving first two reads in the while condition:
Edit: As per James Kanze's comment, you're taking an adress past the end of
Gtable
array, which is what causes segfault. You could pass the size ofGtable
as argument to your fillTable() function (f.ex.void fillTable(int table_size)
) and checkslot
is in bounds before each read.*根据 James 的评论进行编辑 - 代码现在使用 good() 检查而不是
!eof() 检查,这将允许它捕获大多数错误。我还加入了 is_open()
检查以确保流与文件关联。*
通常,您应该尝试按如下方式构建循环中的文件读取结构:
此解决方案是可取的(在我看来),因为它不依赖于添加随机数
break
在循环内部,循环条件是一个简单的 good() 检查。这使得代码更容易理解。
*Edited in response to James' comment - the code now uses a good() check instead of a
!eof() check, which will allow it to catch most errors. I also threw in an is_open()
check to ensure the stream is associated with the file.*
Generally, you should try to structure your file reading in a loop as follows:
This solution is desirable (in my opinion) because it does not rely on adding random
break
s inside the loop, and the loop condition is a simple good() check. This makes thecode easier to understand.