1

I am trying to read a CSV file in c89 using scanf:

FOO,2,3
BAR,5,4
...

This is what I have tried:

#include <stdio.h>

int main() {

    char code[10];
    double a,b;

    while( scanf("%s,%lf,%lf", code, &a, &b)!=EOF ) {
        printf("> %s\n", code);
        printf("> %s,%lf,%lf\n", code, a, b);
    }

    return 0;
}

This is the output I get:

$ ./a.out
A,2,3
> A,2,3
> A,2,3,0.000000,0.000000
B,5,4
> B,5,4
> B,5,4,0.000000,0.000000
$ 

This is the output I was expecting from the above code:

$ ./a.out
A,2,3
> A
> A,2.000000,3.000000
B,5,4
> B
> B,5.000000,4.000000
$ 

Edit

As per the comment provided I have tried:

#include <stdio.h>

int main() {

    char code[10];
    double a,b;

    while( scanf("%9[^,],%lf,%lf", code, &a, &b)!=EOF ) {
        printf("> %s\n", code);
        printf("> %s,%lf,%lf\n", code, a, b);
    }

    return 0;
}

And I get:

$ cat > test.txt
A,2,3
B,4,5
C,5,6
$ cat test.txt | ./a.out 
> A
> A,2.000000,3.000000
> 
B
> 
B,4.000000,5.000000
> 
C
> 
C,5.000000,6.000000
> 

> 
,5.000000,6.000000
$

Apparently the first record is properly processed but not the subsequent ones.

Also I have the question about what the 9 does and if the whole %9[^,] is part of c89.

M.E.
  • 4,955
  • 4
  • 49
  • 128
  • 1
    Did you try replacing your scanf reader's `%s` with `%9[^,]` ? – WhozCraig May 31 '21 at 21:31
  • You probably want to test the return value of `scanf` against 3, in case you read some of the elements but not all. – Nate Eldredge May 31 '21 at 21:32
  • @WhozCraig I have tried your solution, see the edit. – M.E. May 31 '21 at 21:39
  • The example input you are showing and desired output don't match. But anyway, `scanf` is going to match the entire string to `%s` and have nothing left to scan for `%lf`. – lurker May 31 '21 at 21:41
  • That is the output I was expecting, I will edit the original question to reflect that more clearly. – M.E. May 31 '21 at 21:43
  • 2
    Your "not the subsequent ones" looks like they have left-over whitespace from the end of the previous line. You might try `" %9[^,]` that is, a space between the opening quote and the percent sign. – Ben Voigt May 31 '21 at 21:52
  • See https://stackoverflow.com/a/12835596/103167 – Ben Voigt May 31 '21 at 21:54
  • 1
    And fyi, the `9` is to ensure your read operation doesn't blast pass the declared buffer size of `code` (10) and subsequently march into the land of undefined behavior. – WhozCraig May 31 '21 at 21:56
  • To learn more about the format strings, please do some web research. The C standard can be found easily, in different versions, as some more resources. You should store the URLs and documents for future usage. – the busybee Jun 01 '21 at 06:56
  • 1
    There are four things `scanf` will return in this case, `[EOF, 0, 1, 2, 3]`; UB if `[0, 1, 2]`, should at least replace `!= EOF` with `== 3`. @thebusybee the C90 standard is difficult to find. – Neil Jun 01 '21 at 14:21

1 Answers1

2

I found a workaround that is reaching each line into a buffer and replacing the commas by spaces first, then I apply the %s.

#include <stdio.h>

int main() {

    char line[256];    
    char code[10];
    double a,b;

    while(scanf("%s", line) != EOF) {

        /* REPLACE ALL , BY SPACES TO SIMPLIFY SCANF USAGE */
        char *p = line;
        while(*p!='\0') {
            if(*p==',') {
                *p = ' ';
            }
            p++;
        }


        sscanf(line,"%s %lf %lf", code, &a, &b);
        printf("> %s\n", code);
        printf("> %s,%lf,%lf\n", code, a, b);               
    }    

    return 0;   

}

Not sure if it is the most elegant solution, but improves readability of the scanf part.

M.E.
  • 4,955
  • 4
  • 49
  • 128