fscanf没有按预期工作

时间:2012-10-11 05:25:13

标签: c++ scanf

我在C ++中使用fscanf如下:

这是我的文本文件:

  

ABCD
  EFGH

“efgh”之后没有空格或新行。 现在这是我的循环:

FILE* fp;
char eof = 0;
do
{
    char str[20];
    fscanf(fp, "%s", str);
    std::cout<<str<<std::endl;
}
while((eof = fgetc(fp)) != eof)

我期望的输出是:

  

ABCD
  EFGH

但我得到的实际输出是:

  

ABCD
  EFGH
  efgh

我调试了一个发现,在读取“efgh”之后,读入eof的值是'\ n'而不是EOF。 环境是linux mint.I想知道为什么总是读取最后一个字符串2次。请咨询

3 个答案:

答案 0 :(得分:2)

最后一个字符串未被读取两次。问题是循环测试继续:

(eof = fgetc(fp)) != eof

这会将fgetc()的返回值分配给eof并检查它是否等于eof。在逻辑上很难做的事情。但是,当文件位于fgetc()时调用EOF时,它会返回-1。对于赋值,它被转换为char,但括号中的子表达式保留值-1(由于类型提升规则)。比较-1到255或-127(取决于char是有符号还是无符号)最终终止循环。

第三次循环,fscanf()失败并且不更新str:这就是为什么相同的值似乎已被读取两次。

要解决这个问题,最直接的技巧是:

do {
 ...
} while (!feof (fp));

但是,在许多操作系统上,feof()fscanf()的效果不佳,因为在fscanf()失败之前,文件结束指示无法可靠地设置。使用

是一种更可靠的O / S抗性技术
do {
    int result = fscanf (fp, ...whatever...);
    if (result < 0)   // end of file or i/o error?
         break;
} while (!feof (fp));

答案 1 :(得分:1)

[跟随Christian Rau在另一个帖子中的评论,我已经 改变了我的第一点,以对应我现在意识到的事情。

您的代码存在一些问题。一些最明显的 是:

  • do...while末尾的条件有未定义的行为。 在表达式eof = fgetc(fp)) != eof中,您可以修改对象 (eof),你可以在表达式的其他地方访问它 确定要存储的值。就标准而言, 任何事情都可能发生,事实上,不同的编译器会有所不同 的东西。

  • 您要将fgetc的结果分配给char,而不是。{ 到intfgetc的返回值在范围内 [0...UCHAR_MAX]EOF(保证为负数)。在 换句话说,它可能比char中的值多一个值。 然后将charEOF进行比较的结果取决于是否 普通char是否已签名。如果它没有签名,它永远不会有 负值,因此永远不会等于EOF。如果签了, 然后在特定字符代码(拉丁语-1中的0xFF或'ÿ')上 检测到文件结束。 fgetc的返回值应始终为。{1}} 已分配给int,只能转换为char 在<{1}}。

  • 的测试之后
  • 您正在使用EOF的结果而不检查。{ 功能成功了。在C ++,IO中,无论是iostream还是fscanf 都不是 预测。由于界面的定义方式,它是 不可能事先告诉你是否会遇到档案结束。 您必须尝试阅读,然后测试读取是否成功。

  • 您正在FILE*使用fscanf而不限制输入 长度。这是一个等待发生的缓冲区溢出。

在C ++中,编写你正在做的事情最自然的方式是:

char[]

使用较旧的C兼容流,您可以写:

std::string word;
while ( anIStream >> word ) {
    //  ...
}

在这两种情况下,检查成功都会控制循环;如果是 在C接口中,您使用格式宽度说明符来确保您 不要超出缓冲区。 (在这两种情况下,你必须定义 即使您只使用,也会在循环外读取变量 他们在循环中。)

答案 2 :(得分:0)

你用eof检查eof。试着像这样检查

while( (eof = fgetc(fp)) != EOF)