从C,数据类型的文件输入

时间:2010-12-20 20:41:56

标签: c input types

提前感谢您花时间阅读我的问题...

/* Binary search for use with Gen_window.comp */
#include <stdio.h>

int main()
{
  char line[1000];
  double sig, E;

  FILE *fp, *fopen();
  fp = fopen("sig_data", "r");

  if (fp==NULL){
        printf("Error opening file!");
  }
  else {
        printf("Processing file...");
  }



  while( (fgets(line, 25, fp) != NULL) ){
        fscanf(fp, "%lf\t%lf", &E, &sig);
        printf("\nThe energy is: %lf eV\nThe corresponding cross section is: %lf barns\n",E, sig);
  }

}

文件中的数字格式为X.XXXXXX + X或X.XXXXXX-X。 C有办法将其指定为输入吗?没有'e'是不是很麻烦。我找不到任何有关输入指数的文档,只返回指数...

我不需要它来打印那种确切的格式,任何其他指数格式都可以。

我意识到我的%lf应该有一些说明符和精度,或者它应该是%e,但我已经尝试了对我有用的一切,所以我基本上把它留空了。

感谢您的帮助。

4 个答案:

答案 0 :(得分:2)

不幸的是,C确实需要“e”。所以你必须自己解析输入。如:

#include <stdio.h>
#include <math.h>

double parse(const char** cursor)
{
    int len;
    double mantissa, exponent;
    char sign;
    sscanf(*cursor, " %lf%[+-]%lf%n", &mantissa, &sign, &exponent, &len);
    *cursor += len;
    return mantissa * pow(10, (sign == '-' ? -exponent : exponent));
}

int main()
{
  char line[1000];
  double sig, E;

  FILE *fp, *fopen();
  fp = fopen("sig_data", "r");

  if (fp==NULL){
        puts("Error opening file!");
        return 1;
  }
  puts("Processing file...");

  while( (fgets(line, 25, fp) != NULL) ){
        const char* cursor = line;
        E = parse(&cursor);
        sig = parse(&cursor);
        printf("The energy is: %e eV\nThe corresponding cross section is: %e barns\n",E, sig);
  }
  return 0;
}

(根据需要添加错误处理)

答案 1 :(得分:2)

Jester和plinth的答案大致正确,但有缺陷。确实无法使库存号解析例程(*scanfatofstrtod)以您拥有的格式处理数字。但是,建议的解决方法很糟糕。首先,我个人认为永远不应该使用*scanfato*,因为他们对畸形输入的处理非常糟糕。更严重的是,十进制到浮点转换需要扩展精度算法以避免精度损失。可以依赖strtod应该用于此问题的例程)来正确地执行此操作,但是分别处理尾数和指数然后以明显的方式组合它们的。您需要一个大于double的中间类型,并且您需要10的幂才能准确计算到最后一位,pow无法可靠地给您。

所以我的建议是动态重写每一行,使strtod可以接受。

  1. 将每一行读入一对字符串缓冲区,在\t分割。我会手动执行此操作,但只要您使用fscanf格式,就可以 使用%s。确保每个缓冲区至少有两个额外的可用空间字节。
  2. 扫描每个缓冲区以查找+-。使用memmove将字符串的所有后续字节向下移动一个。将e戳到符号原始位置的缓冲区中。 (如果您手动执行步骤1,则可以将此步骤与该步骤的循环结合使用。)
  3. 您现在拥有strtod可以处理的格式的数字。

答案 2 :(得分:0)

如果没有指数,fscanf将不会帮助你,所以你自己。这意味着将字符串拆分为+/-,在左边调用atof(),在右边调用atoi()(或atof())并将第一个乘以第一个到第10个再增加到第二个:

char *splitAt(char *s, char *stops)
{
   if (!s) return 0;
   char *t;
   for (t = s; *t && strchr(stops, *t) == NULL; t++)
       ;
   int len = t - s;
   t = malloc(len + 1);
   strncpy(t, s, len);
   t[len] = '\0';
   return t;
}


double parse_my_float(char *input)
{
    /* allocates a new string */
    char *mantissaStr = splitAt(input, "+-"); /* check for null! */
    double mantissa = atof(mantissaStr);
    int len = strlen(mantissaStr);
    free(mantissaStr);
    int exponent = atoi(input + len);
    return mantissa * pow(10, exponent);
}

答案 3 :(得分:0)

如何使用strtok和strtod,它应该很适合你。使用sscanf或fscanf非常容易出错。见下文:

const char* insertE(char* out, const char* src)
{
    char* p = out;
    while (*src) {
        if (*src == '+' || *src == '-') {
            *p++ = 'e';
        }
        *p++ = *src++;
    }
    return out;
}
.
.
.
char line[1000];
char tmp[100];
double sig, E;
FILE *fp;
char* end;

fp = fopen("sig_data", "r");
if (fp==NULL){
    printf("Error opening file!");
    return;
}
else {
    printf("Processing file..."); 
    while(! feof(fp) && (fgets(line, 1000, fp) != NULL) ) {            
        E = strtod(insertE(tmp, strtok(line, "\t")), &end);
        sig = strtod(insertE(tmp, strtok(NULL, "\t")), &end);
        printf("\nThe energy is: %lf eV\nThe corresponding cross section is: %lf barns\n", E, sig);
    }
    fclose(fp);
}

此附带通知,此代码假定输入文件格式正确。