Question

I have the following line of text left in a file that I wish to parse one digit by one digit:

10001111001000101001010001100000101110000102

however when I use the format specifier %d fscanf returns an EOF indicator and not a digit. This is contrasted to when I use %s where it returns what I expect though it does it all at once and in a string.

So when I change (as well as the type of he from int to char[250])

if (fscanf(f, "%d", &character) != EOF)

to

if (fscanf(f, "%s", &character) != EOF)
Was it helpful?

Solution

If you want to scan digit by digit, you need to use "%1d" as the format.

Otherwise, it reads the whole line (apart from the newline) as the number and invokes undefined behaviour when it converts the large decimal number into a 32-bit int. Note that the mnemonic for d is not 'digit' but 'decimal', as opposed to 'o' for octal, 'x' for hexadecimal, and 'i' for integer in decimal, octal or hexadecimal according to the normal prefixes (leading 0 for octal, 0x for hex, or decimal otherwise).

It is still not entirely clear why it returns EOF, but with undefined behaviour, any response is valid.

The standard (ISO/IEC 9898:2011 Section 7.21.6.2 The fscanf() function, Para 10) says (in the relevant part):

If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.

There is quite a lot of verbiage about the behaviour under error conditions, but this is the crucial one here. Since the behaviour is undefined, getting EOF is a valid and relatively benign response. It would be interesting to investigate whether the file stream is in the state where feof(f) or ferror(f) returns true. There's no obvious reason why it should be except that you do not normally get EOF from fscanf() unless one or the other is true.

OTHER TIPS

"%d" format-specifier inside a scanf family function will cause the function to look for a digit sequence, that is terminated with the first non-digit character encounter. In your case, using "%d" will consume up all the digits at once.

If "%d" didn't do as such, then you'd only be able to read single-digit numbers with it, which would be barely any formatted-input.

"%s" format-specifier causes a character sequence to get consumed, which is to get terminated with a white-space character, or end of file.

What you are looking for here, is to read the input character-by-character. You can do that with "%c" format-specifier. Afterwards, you can interpret the obtained character to its digital value.

For example; you could read the first '1' character, then subtract a '0' character from it, which would yield '1' - '0' == 1, the thing you seem to want.

fscanf returns the number of input items assigned or EOF in the case of failure. That is only one problem. The other is that it will continue to consume characters from the input string until it encounters a \0 character or a non-digit (in the %d case). Passing it the address of a single character is not a valid thing to do either. You could do something like the following instead:

char *p;
for (p=&input_string[0]; isdigit(*p); p++) {
    int digit = (int)(*p - '0');
    /* process digit */
}

If you want to use one of the scanf functions, create a string of two characters - the digit being processed and \0. Then sscanf that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top