views:

234

answers:

3

I am trying to read file with 30 rows and 5 columns with separator of "tab". Each time I get only part of the rows. In the windows environment it's working good. Any idea why in unix it is not working?

while (fscanf(FFMapFile, "%s\t%s\t%s\t%s\t%s\t", fnfMap[i].COS_ID, fnfMap[i].FF_First_Act, fnfMap[i].FF_Next_Act, nfMap[i].Free_FF_allowed, fnfMap[i].FF_Change_Charge) != EOF)
{ 
    sprintf(s,"%s\t%s\t%s\t%s\t%s\t", nfMap[i].COS_ID, fnfMap[i].FF_First_Act, fnfMap[i].FF_Next_Act, fnfMap[i].Free_FF_allowed, fnfMap[i].FF_Change_Charge);
    error_log(s,ERROR);
    i++; }
A: 

On success, the fscanf returns the number of items succesfully read. This count can match the expected number or be less in case of a matching failure.

You should check fscanfs return value to see which line isn't parsed correctly and examine your input data.

stacker
+1  A: 

The \t characters in your fscanf() string are not necessary - tabs are whitespaces, so you may just as well say "%s%s%s%s" - conceivably, the two scanf implementations are treating them differently. Also, you should be checking for fscanf returning a value other than EOF but not equal to the number of expected conversions, which would indicate a conversion error of some sort.

anon
"you may just as well say "%s%s%s%s" " -- No, even when we fix your typo to "%s%s%s%s%s" (five strings instead of 4) it still won't be a substitute. But "%s%s%s%s%s\t" to vacuum up trailing whitespace would be a substitute.
Windows programmer
+1  A: 

Check the return value from fscanf() more carefully; it will return, for example, 3 if it matches 3 fields. You might want to be careful about the sizes of the various strings to avoid buffer overflows - that is, however, probably a subject for another day.

The possibility which strikes me is that the last tab in the format string might be better as a newline - but fscanf() normally takes a fairly liberal attitude towards white space in the format strings and data.

This simplified (but complete, working) version of your code behaves more or less sanely on MacOS X.

#include <stdio.h>

int main(void)
{
    char b1[20], b2[20], b3[20], b4[20], b5[20];
    while (fscanf(stdin,"%s\t%s\t%s\t%s\t%s\t", b1, b2, b3, b4, b5) == 5)
        printf("%s\t%s\t%s\t%s\t%s\n", b1, b2, b3, b4, b5);
    return 0;
}

However, it did treat a string 'k k k k k' (5 single letters separated by blanks) as equivalent to separated by 5 tabs. The problem, therefore, is that section §7.19.6.2 of the C standard specifies:

The format is composed of zero or more directives: one or more white-space characters, an ordinary multibyte character (neither % nor a white-space character), or a conversion specification.

Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier.

Also, with regards to the '%s' specifier, it says:

Matches a sequence of non-white-space characters.

To force matching of actual tabs, you'd have to work quite a bit harder. It would be much easier to resort to the 'read a line into a buffer (fgets()) and split it manually'. This will also allow you to enforce 5 words on a line and you can generate an error or warning if there are too few or too many fields. With fscanf(), you cannot do that. If you type 8 words on a line, it will read the first five the first time, then the remaining three words on the line plus the first two on the next, and so on.

Jonathan Leffler