Paul Filch
Paul Filch

Reputation: 917

Using scanf in C

My question seems to be very simple but I can't find an answer on Google.

I'd like to know what while (fscanf(inFile, "%[^ \n] ", string) != EOF) does. I'm trying to read in a string from a file by using the above.

However, I am not exactly sure what this statement does, specifically the %[^ \n] part. I know that it will loop until end of file, but is "string" a number value or some other value? Also, how can I use it?

For example, for a sentence "I like trees", what is the string value equivalent to?

Thank you in advanced.

Upvotes: 0

Views: 220

Answers (4)

chux
chux

Reputation: 153338

while (fscanf(inFile, "%[^ \n] ", string) != EOF) has huge problems.

The format string "%[^ \n] " is made up of 2 directives: "%[^ \n]" and " ".

"%[^ \n]" is a format specifier made up of a scanset. The scanset consists of all char except ' ' and '\n'. So fscanf() looks for 1 or more characters that are in the scanset and saves them to string.

"%[^ \n]" has 2 problems:
1) If the first character encountered is not in the scanset, fscanf() ungets that character back to inFile and the function returns 0. No further scanning occurs. So if inFile begins with a ' ', code puts nothing in string, inFile is not advanced and subsequent code is set up for UB or an infinite loop!

2) The numbers of characters to save in string is unbounded. So if inFile begins with more that the sizeof(string)-1 char in the scanset, undefined behavior ensues.

" " directive tells fscanf() to consume 0 or more white-space char. This can be confusing should inFile have the value stdin. In that case, the user needs to enter some non-white-space after the ' ' or '\n'. Since stdin is usually line buffered, that means something like "abc\ndef\n" needs to be entered before scanf() saves "abc" and returns 1. The "def\n" is still in stdin.

Recommend instead:

char string[100];
while (fscanf(inFile, "%99s", string) == 1) {
  ...
}

"%99s" will consume optionally leading white-space, then up to 99 non-white-space char, appending the usual \0.

Upvotes: 0

ajay
ajay

Reputation: 9680

Note the space after the caret ^ and the trailing space in the format string "%[^ \n] " of fscanf.

fscanf(inFile, "%[^ \n] ", string)

The above statement means that fscanf will read from the stream inFile and match any nonempty sequence of characters which does not contain either a space ' ' or a newline '\n' and write them into the buffer pointer to by the next argument which is string, and then read and discard any number of (including zero) whitespace characters (meant by the trailing space in the format string). The buffer pointed to by string must be large enough for any such sequence of characters plus the terminating null byte added automatically. If the buffer is not large enough, then fscanf will overrun it invoking undefined behaviour and most likely causing program crash due to segfault. You must guard against it by specifying maximum field width which should be one less than the length of the buffer to accommodate the terminating null byte.

fscanf returns the total number of input items successfully matched and assigned, which in this case, is one. It will return EOF when the end of file is reached in the stream inFile. Therefore the while loop condition means that fscanf will read such a sequence of characters and write it into the buffer string till the end of file is reached in the stream inFile.

You should change your while loop to -

// assuming string is a char array

char string[100];

while(fscanf(inFile, "%99[^ \n] ", string) == 1) {
    // return value 1 of fscanf means fscanf call was successful
    // do stuff with string
}

Upvotes: 2

Aakash Jain
Aakash Jain

Reputation: 1973

"%[^ \n]" basically it matches every thing except a \n or a ' ' character.

The fscanf statement you have will read everything from the file pointed to by inFile and then stores what it read into a string named string, which should be declared as char string[500] (or a similar sufficiently large value). Everytime it successfully reads a character, it returns it.

Now since you need a way for the while loop to quit after reading the file, you are comparing the return of fscanf to EOF, which is the special end-of-file character.

EDIT: corrected const char*

Upvotes: 0

Ankit Kumar
Ankit Kumar

Reputation: 1463

%[^ \n] tells fscanf to read all the characters excluding \n and space.

Upvotes: 2

Related Questions