在C中使用fscanf存储双精度或字符串值时出现问题

3gtaxfhh  于 2023-08-03  发布在  其他
关注(0)|答案(2)|浏览(82)

所以我被要求在课堂上写一个小程序。我正在学习用C编写代码,当试图根据其类型将值存储在不同的变量中时,我对这个函数和fscanf函数的使用有问题。
它应该做的是由我的老师写在注解中,其余的是我的代码(除了包含的库之外,我不应该使用任何其他库):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*  A) Tries to read a double from the file and asign its value to the double pointed by num. If it was possible returns 1.
    B) In other case, tries to read a string up to 31 chars and stores its value on the string
    pointed by op, if it was possible returns 2.
    C) In any other case it returns 0 (end of file, etc)*/

int num_or_op(FILE* f, double *num, char *op) {
    
    int aux;
    int read = 0;
    read = fscanf(f, "%lf", num);
    if (read==-1) /*eof*/
    return 0;
    if (read==0){
        aux = fscanf(f, "%31s", op);
        if (aux>0){
            read=2;
        }
    }

return read;
}

字符串
我发现的问题是,按照这些步骤,程序跳过了一些字符。我在while块中调用这个函数来存储所有数据。如果我引入一个文件,例如,1 2 + 3,它读取1和2,那么它无法正确存储+,而是在下一个fscanf中执行,它只是扫描数字3并将其添加到op指向的字符串中。我想当fscanf返回0时,如果这次格式正确,下一次调用fscanf会读取之前无法读取的相同字符,但显然它不这样工作,或者我可能做错了什么。我能够想出不同的替代方案,但是有没有办法按照指定的顺序,A,B,C并直接从文件中阅读fscanf(例如,不使用fgets来获取一行)?我被要求用这个特定的功能来做。如果有关系的话,我正在用gcc -ansi -pedantic -Wall -Wextra -Werror -o program program.c编译。

b1payxdu

b1payxdu1#

正确答案是由@user3386109在评论中给出的,所以我在这里添加解释以结束这个问题。
在这个函数发生转换错误后,标准只需要一个字符的后推,而我使用的实现满足最低要求的后推。输入-.a就是一个很好的例子。解析器需要读取三个字符来确定输入不是有效的double。如果它只回推一个字符,则-.将丢失。在我的例子中,+和space被读取,只有space被推回。我的程序运行的是C版本的C89/C90。

jdzmm42g

jdzmm42g2#

你的代码似乎在为我工作:

#include <stdio.h>
#include <string.h>
#include <stdio.h>

int num_or_op( FILE *f, double *num, char *op )
{
  int aux;
  int read = 0;
  read = fscanf( f, "%lf", num );
  if ( read == -1 )
    return 0;
  if ( read == 0 )
  {
    aux = fscanf( f, "%31s", op );
    if ( aux > 0 )
      read = 2;
  }

  return read;
}

int main( void )
{
  char op[32] = {0};
  double d = 0.0;

  int r;

  do
  {
    r = num_or_op( stdin, &d, op );
    printf( "num_or_op returned %d", r );
    if ( r == 1 )
      printf( ": d = %f", d );
    else if ( r == 2 )
      printf( ": op = %s", op );
    putchar ('\n' );
  } while ( r != 0 );
 
  return 0;
}

字符串
使用1 2 + 3作为输入:

$ echo 1 2 + 3 | ./num_or_op
num_or_op returned 1: d = 1.000000
num_or_op returned 1: d = 2.000000
num_or_op returned 2: op = +
num_or_op returned 1: d = 3.000000
num_or_op returned 0


再加上一些令人讨厌的输入:

$ echo 1 2 + 3 4 - foo 5 / 6 | ./num_or_op
num_or_op returned 1: d = 1.000000
num_or_op returned 1: d = 2.000000
num_or_op returned 2: op = +
num_or_op returned 1: d = 3.000000
num_or_op returned 1: d = 4.000000
num_or_op returned 2: op = -
num_or_op returned 2: op = foo
num_or_op returned 1: d = 5.000000
num_or_op returned 2: op = /
num_or_op returned 1: d = 6.000000
num_or_op returned 0


也许你的问题是在调用代码?
话虽如此,我确实对你的代码有一些风格上的问题。比如使用-1而不是EOF,或者需要第二个aux变量,等等。事实证明,该函数可以更清晰:

int num_or_op( FILE *f, double *num, char *op )
{
  int read = 0;

  if ( fscanf( f, "%lf", num ) == 1 )
    read = 1;
  else if ( fscanf( f, "%31s", op ) == 1 )
    read = 2;

  return read;
}

相关问题