1

I'm trying to read the values in those lines to the variables with sscanf and I'm getting very weird results. It works with some lines as long as I use floats, but with other similar lines with floats it doesn't work, and if I use doubles instead of floats it never works properly.

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

void debug(char* line,int* year, int* month, int* day, double* temp, double* uncertainty,
char country[100]){
    int result;
    result = sscanf(line, "%i - %i - %i, %lf , %lf , %s", year, 
    month, day, temp, uncertainty, country);
    printf("%i-%i-%i,%f,%f,%s\n",*year, *month, *day, *temp, 
    *uncertainty, country);
    printf("Result:%i\n", result);
}

void debug_f(char* line, int* year, int* month, int* day, float* temp, float* uncertainty,
char country[100]){
    int result;
    result = sscanf(line, "%i - %i - %i, %f , %f , %s", year, 
    month, day, temp, uncertainty, country);
    printf("%i-%i-%i,%lf,%lf,%s\n",*year, *month, *day, *temp, 
    *uncertainty, country);
    printf("Result:%i\n", result);
}

int main(){
    char* error = "1943-09-01,29.27,0.403,Yemen";
    char* working = "1972-03-01,4.787,0.342,Slovakia";
    int year1, year2, year3, year4;
    int month1, month2, month3, month4;
    int day1, day2, day3, day4;
    double temp1, temp2;
    double uncertainty1, uncertainty2;
    float temp3, temp4;
    float uncertainty3, uncertainty4;
    char country1[100], country2[100], country3[100], country4[100];
    debug(error, &year1, &month1, &day1, &temp1, &uncertainty1, country1);
    debug(working, &year2, &month2, &day2, &temp2, &uncertainty2, country2);
    debug_f(error, &year3, &month3, &day3, &temp3, &uncertainty3, country3);
    debug_f(working, &year4, &month4, &day4, &temp4, &uncertainty4, country4);
}

This is the output I get on my machine:

1943-0-0,0.000000,0.000000,�\��

Result:2

1972-3-1,0.000000,0.000000,Slovakia

Result:6

1943-0-0,0.000000,0.000000,

Result:2

1972-3-1,4.787000,0.342000,Slovakia

Result:6

chilliefiber
  • 571
  • 2
  • 7
  • 18
  • 2
    Please provide a [MCVE]. – Christian Gibbons May 18 '18 at 19:01
  • @ChristianGibbons is it good now? – chilliefiber May 18 '18 at 19:39
  • 1
    Use `%lf` for doubles. – Eugene Sh. May 18 '18 at 19:43
  • @EugeneSh. that doesn't change anything either. Also, see https://stackoverflow.com/questions/4264127/correct-format-specifier-for-double-in-printf From C99 forward `%lf` and `%f` are the same thing. – chilliefiber May 18 '18 at 19:47
  • 1
    They are the same thing for `printf`, but not `scanf`. You have to use `%lf` there. – Eugene Sh. May 18 '18 at 19:47
  • @EugeneSh. I just tried it with `%lf` and it changed absolutely nothing. – chilliefiber May 18 '18 at 19:48
  • 1
    Then post the code with `%lf`, as it is an obvious error. – Eugene Sh. May 18 '18 at 19:49
  • @EugeneSh. done! – chilliefiber May 18 '18 at 19:50
  • 1
    You didn't change it in `debug_f`, yet it looks like some more problems are there – Eugene Sh. May 18 '18 at 19:51
  • @EugeneSh. Did it now, didn't realise it also applied to floats, especially since it worked with `%f` for that example. Again, this didn't change anything in the output, so I guess it is only tangential to the problem. – chilliefiber May 18 '18 at 19:53
  • 3
    Oh, it's a funny issue :) `%i` is for signed integers. You have dashes, which are read as minus signs. Use `%u` instead. – Eugene Sh. May 18 '18 at 19:57
  • @EugeneSh correct. Two issues float value read to double variable, and signed int. – Vinay P May 18 '18 at 20:03
  • 2
    scanf family needs to specify the length of the floating point type so it knows how it should be storing the data into the variable pointed to. printf doesn't care since it will promote a float to a double regardless. – Christian Gibbons May 18 '18 at 20:15
  • @EugeneSh. I think there is something to explain, because `"%u - %u - %u, %lf , %lf , %s"` does NOT work for floats, even though you said I had to use `%lf`. However, when I switch to `"%u - %u - %u, %f , %f , %s"` it works for the floats. – chilliefiber May 18 '18 at 20:41
  • 1
    Of course it doesn't. Because `%f` is for float. `%lf` is for `double`.. If you mix these, the behavior is undefined. – Eugene Sh. May 18 '18 at 20:43
  • @EugeneSh. [Re](https://stackoverflow.com/questions/50417719/trouble-getting-sscanf-to-work-correctly-with-certain-inputs#comment87852387_50417719): The `"-"` of the string are not read as minus signs. Instead they are matched and consumed by the `"-"` of the format. Using `"%u"` would insure a decimal interpretation of text, unlike `"%i"`, yet a `"%d"` is called for here. – chux - Reinstate Monica Nov 08 '18 at 19:53

2 Answers2

1

Try removing the space used in between date elements in sscanf.

sscanf(line, "%i-%i-%i, %f , %f , %s", 
               &int1, &int2,
               &int3, &double1, &double2,
               s);

As EugeneSh pointed above its signed integer, and reading float to a double.

Vinay P
  • 617
  • 3
  • 13
0

"%i" differs from "%d" when scanning

"1943-09-01,29.27,0.403,Yemen"; fails because "09" is not scanned into an int as 9 with "%i".

In the below code, when scanning for month, sscanf(), using "%i", encounters "09". Since it leads with a'0', that switches interpretation to octal. As '9' is not an octal digit, month is assigned 0 and scanning continues with " - %i, %lf , %lf , %s". Since '9' does not match '-', scanning stops and reports 2 successful conversions.

sscanf(line, "%i - %i - %i, %lf , %lf , %s", year,  month, day, temp, uncertainty, country);

Suggested alternative

Use "%d" instead of "%i" to insure decimal interpretation.

Use width limits when saving a string.

Use "%n" to detect end of scan and look for extra junk.

void debug(const char* line, int* year, int* month, int* day, 
    double* temp, double* uncertainty, char country[100]){
  int n = 0;
  int result = sscanf(line, "%d - %d - %d , %lf , %lf , %99s %n", 
      year, month, day, temp, uncertainty, country, &n);
  printf("Result:%i\n", result);

  if (n > 0 && line[n] == '\0') {
    printf("%i-%i-%i,%f,%f,%s\n",
        *year, *month, *day, *temp, *uncertainty, country);
  } else {
    printf("<%s> failed\n", line);
  }
}

Note that %s will not fully read country names like "Sri Lanka", but only the first "word" "Sri". Depending on coding goals, consider:

  int result = sscanf(line, "%d - %d - %d , %lf , %lf , %99[^\n] %n", 
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256