sscanf和正确的格式文件

时间:2013-07-10 16:53:07

标签: c linux scanf

我的sscanf功能有问题。更具体一点,我想从txt文件中读取一个浮点数(我只想要一行浮点数),但sscanf无法识别这些情况:

3.4t

4.t6

4.5 6.5

(this is an empty line)

我使用此代码:

 #define LUNRIGA 200     

 char riga[LUNRIGA+1];

 while (fgets(riga,LUNRIGA,f) != NULL) {
      r = sscanf(riga,"%f",&numeri[i]);
      if (r == 1) { /* riga valida */
         printf("OK");
      }else{
         printf("Error");
         return 1; 
      }    
 }

2 个答案:

答案 0 :(得分:1)

众所周知,

sscanf对输入很挑剔。使用strtodstrtol可以获得更好的运气 - 他们可以读取一个值,即使它后面跟着垃圾。按如下方式更改您的代码:

#define LUNRIGA 200     

char riga[LUNRIGA+1];
char* tempPtr;

while (fgets(riga,LUNRIGA,f) != NULL) {
  numeri[i] = strtof( riga, &tempPtr );
  if (tempPtr > riga) { /* riga valida */
     printf("OK");
  }
  else {
     printf("Error");
     return 1; 
  }    
}

请注意,您似乎没有在循环中增加i - 您可能想知道这实际上是否是您想要的,或者您是否希望每次获得有效时都增加它数字(假设你不只是想要最后一个值,而是所有这些......)

作为strtod行为的一个小演示,我写了几行代码:

#include <stdio.h>
#include <stdlib.h>
int main(void) {
  char* s1="123.45t";
  char* p1;
  char* s2 = "   notanumber";
  double d1, d2;
  d1 = strtod(s1, &p1);
  printf("the number is %.2lf; the pointer is now %p; string is at %p\n", d1, s1, p1);
  d2 = strtod(s2, &p1);
  printf("the number is %.2lf; the pointer is now %p; string is at %p\n", d2, s2, p1);
}

这个输出是:

The number is 123.45; the pointer is now 0x400668; string is at 0x40066e
The number is 0.00; the pointer is now 0x400670; string is at 0x400670

正如您所看到的,当读取垃圾时,返回的指针指向字符串的开头 - 表示“失败”。当它成功时,指针指向“我停止读取的位置”,这是“成功将一些字符串转换为双倍后。”

答案 1 :(得分:0)

如果你想确定线路上没有垃圾,可以使用%n指令找出转换停止的位置,并决定如何处理后续线路:< / p>

char  riga[LUNRIGA];
float numeri[NUM_VALUES];
int   offset;
int   i;

for (i = 0; i < NUM_VALUES && fgets(riga, sizeof(riga), f) != NULL; i++)
{
    int r = sscanf(riga, "%f%n", &numeri[i], &offset);
    if (r == 1 && riga[offset] == '\n')
        printf("OK (got %f from <<%s>>\n", numeri[i], riga);
    else
    {
        printf("Error processing <<%s>>\n", riga);
        return 1; 
    }    
}

您可以在sscanf()之前进行一些额外的处理,例如检查您是否读取了换行符(因此还没有要读取超长行的剩余部分)并删除换行(但是你需要改变条件)。

请注意sizeof(riga)的使用,并通过对代码强加numeri循环来检查是否有for次溢出,并且每封邮件末尾都有换行符