2010-12-20 106 views
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,但我已经尝试了所有对我有意义的事情,所以我基本上将它留空。

感谢您的帮助。

回答

2

小丑和底座的答案是广泛正确的,但有缺陷的。确实没有办法使股票号码解析例程(*scanf,atof,strtod)按照您的格式处理数字。但是,建议的解决方法很糟糕。首先,我个人认为*scanfato*不应该被使用,因为它们处理格式错误的输入可怕。更严重的是,小数到浮点数转换需要扩展精度算法以避免精度损失。 strtod(这是应为应用于此问题的例程)可以依赖于正确执行此操作,但分别处理尾数和指数,然后以明显的方式组合它们,确实不是而是。你需要一个大于double的中间类型,并且你需要10个功率精确地计算到最后一位,而这个pow不能可靠地给你。

所以我的建议是重写每一行以使其可以被strtod接受。

  1. 将每一行读入一对字符串缓冲区,拆分为\t。我会手工做到这一点,但只要您只使用%s格式,您可以大概摆脱使用fscanf。确保每个缓冲区至少有两个额外的可用空间字节。
  2. 扫描每个缓冲区的+-。使用memmove将该字符串的所有后续字节向下移一位。将e拨到标志原始位置的缓冲区中。 (如果您手动执行第1步,则可以将该步骤与该步骤的循环组合起来。)
  3. 您现在有一个strtod可以处理的格式的数字。
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); 
} 
+0

我想,你真正想说的是,我应该编写一个python脚本来将输入文件放在正确的格式中;-)它应该是像X.XXXXXXe + XXX这样的东西吗? – lollygagger 2010-12-20 21:47:17

+0

也许,我假设输入格式是不可变的或不切实际的可变的。 – plinth 2010-12-20 21:56:15

+0

你当然有权假设!我正在对C进行传球,这让我非常憎恶,而不是传球给你!对不起,如果我似乎嗤之以鼻... – lollygagger 2010-12-20 22:20:37

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

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

+0

从解析函数,在sscanf语句中,你的意思是“...%d \ n”? – lollygagger 2010-12-20 21:41:18

+0

你在问%n吗?这存储了处理的字符数。我用它来推进游标。 – Jester 2010-12-23 13:59:44

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

这附带了一个通知,该代码假定输入文件格式正确。