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

发布于 2024-10-09 02:50:27 字数 765 浏览 2 评论 0原文

预先感谢您花时间阅读我的问题...

/* 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,但我已经尝试了对我有意义的所有内容,所以我基本上将其留空。

感谢您的帮助。

thanks in advance for taking the time to read through my question...

/* 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);
  }

}

Numbers in the file are of the format X.XXXXXX+X or X.XXXXXX-X accordingly. Does C have a way to specify this as input? Is it a bother that there is no 'e'. I cannot find any documentation that tells about inputing exponential, only returning exponential...

I do not need it to print that exact format, any other exponential format would be fine.

I realize there should be some specifiers and precision in my %lf, or maybe it should be %e, but I have tried everything that makes sense to me, so I am basically leaving it blank.

Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酒几许 2024-10-16 02:50:27

小丑和底座的答案大体上是正确的,但有缺陷。确实没有办法让库存数字解析例程(*scanfatofstrtod)以您所拥有的格式处理数字。但是,建议的解决方法很糟糕。首先,我个人认为永远不应该使用 *scanf 和ato* ,因为它们对格式错误的输入的处理非常糟糕。更严重的是,十进制到浮点的转换需要扩展精度算术以避免精度损失。可以依靠 strtod (这是解决此问题应该使用的例程)来正确地完成此操作,但是分别处理尾数和指数,然后将它们组合在显然时尚。您需要一个大于 double 的中间类型,并且需要精确计算到最后一位的 10 次幂,而 pow 无法可靠地为您提供这一点。

因此,我的建议是即时重写每一行,使其可以被 strtod 接受。

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

Jester and plinth's answers are broadly correct, but flawed. There is indeed no way to make the stock number-parsing routines (*scanf, atof, strtod) process a number in the format you have. However, the suggested workarounds are bad. First off, it is my personal opinion that *scanf and ato* should never be used, due to their horrifically bad handling of malformed input. More seriously, decimal-to-float conversion requires extended-precision arithmetic to avoid loss of accuracy. strtod (which is the routine that should be used for this problem) can be relied on to do this correctly, but processing the mantissa and exponent separately and then combining them in the obvious fashion does not. You need an intermediate type bigger than double and you need powers of 10 that are accurately computed all the way to the last bit, which pow doesn't reliably give you.

So my recommendation is to rewrite each line on the fly to make it acceptable to strtod.

  1. Read each line into a pair of string buffers, splitting at \t. I would do this by hand, but you can probably get away with using fscanf as long as you only use %s formats. Make sure that each buffer has at least two extra bytes of space available.
  2. Scan each buffer for the + or -. Use memmove to shift that and all subsequent bytes of the string down one. Poke an e into the buffer at the original position of the sign. (If you do step 1 by hand you can combine this step with the loop for that step.)
  3. You now have the number in a format that strtod can process.
天涯沦落人 2024-10-16 02:50:27

不幸的是,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;
}

根据需要添加错误处理)

Unfortunately C does require the "e". So you will have to parse the input for yourself. Such as:

#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;
}

(Add error handling as needed)

静待花开 2024-10-16 02:50:27

如果没有指数,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);
}

fscanf won't help you if there are no exponents so you're on your own. That means splitting the string at the +/-, calling atof() on the left, atoi() (or atof()) on the right and multiplying the first by the first to 10 raised to the second:

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);
}
寻找我们的幸福 2024-10-16 02:50:27

使用 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);
}

此代码附带一个通知,该代码假定输入文件的格式完全正确。

How about using strtok and strtod, it should do it for you quite nicely. Using sscanf or fscanf very error prone. See below:

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);
}

This comes with a notice that this code assumes the input file is formatted exactly correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文