Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fscanf problem with reading in String

Tags:

c

scanf

I'm reading in a .txt file. I'm using fscanf to get the data as it is formatted. The line I'm having problems with is this:

result = fscanf(fp, "%s", ap->name);

This is fine until I have a name with a whitespace eg: St Ives So I use this to read in the white space:

result = fscanf(fp, "%[^\n]s", ap->name);

However, when I try to read in the first name (with no white space) it just doesn't work and messes up the other fscanf.

But I use the [^\n] it works fine within a different file I'm using. Not sure what is happening.

If I use fgets in the place of the fscanf above I get "\n" in the variable.

Edit//

Ok, so if I use:

result = fscanf(fp, "%s", ap->name);
result = fscanf(fp, "%[^\n]s", ap->name);

This allows me to read in a string with no white space. But When I get a "name" with whitespace it doesn't work.

like image 959
jumm Avatar asked Dec 12 '09 14:12

jumm


People also ask

Can fscanf read string?

fscanf type specifiers String of characters. This will read subsequent characters until a whitespace is found (whitespace characters are considered to be blank, newline and tab).

How does fscanf work with strings?

The fscanf() function reads data from the current position of the specified stream into the locations that are given by the entries in argument-list , if any. Each entry in argument-list must be a pointer to a variable with a type that corresponds to a type specifier in format-string .

Does fscanf only read one line at a time?

This means that even a tab ( \t ) in the format string can match a single space character in the input stream. Each call to fscanf() reads one line from the file.


2 Answers

One problem with this:

result = fscanf(fp, "%[^\n]s", ap->name);

is that you have an extra s at the end of your format specifier. The entire format specifier should just be %[^\n], which says "read in a string which consists of characters which are not newlines". The extra s is not part of the format specifier, so it's interpreted as a literal: "read the next character from the input; if it's an "s", continue, otherwise fail."

The extra s doesn't actually hurt you, though. You know exactly what the next character of input: a newline. It doesn't match, and input processing stops there, but it doesn't really matter since it's the end of your format specifier. This would cause problems, though, if you had other format specifiers after this one in the same format string.

The real problem is that you're not consuming the newline: you're only reading in all of the characters up to the newline, but not the newline itself. To fix that, you should do this:

result = fscanf(fp, "%[^\n]%*c", ap->name);

The %*c specifier says to read in a character (c), but don't assign it to any variable (*). If you omitted the *, you would have to pass fscanf() another parameter containing a pointer to a character (a char*), where it would then store the resulting character that it read in.

You could also use %[^\n]\n, but that would also read in any whitespace which followed the newline, which may not be what you want. When fscanf finds whitespace in its format specifier (a space, newline, or tab), it consumes as much whitespace as it can (i.e. you can think of it consuming the longest string that matches the regular expression [ \t\n]*).

Finally, you should also specify a maximum length to avoid buffer overruns. You can do this by placing the buffer length in between the % and the [. For example, if ap->name is a buffer of 256 characters, you should do this:

result = fscanf(fp, "%255[^\n]%*c", ap->name);

This works great for statically allocated arrays; unfortunately, if the array is dyamically sized at runtime, there's no easy to way to pass the buffer size to fscanf. You'll have to create the format string with sprintf, e.g.:

char format[256];
snprintf(format, sizeof(format), "%%%d[^\n]%%*c", buffer_size - 1);
result = fscanf(fp, format, ap->name);
like image 110
Adam Rosenfield Avatar answered Sep 28 '22 14:09

Adam Rosenfield


Jumm wrote:

If I use fgets in the place of the fscanf above I get "\n" in the variable.

Which is a far easier problem to solve so go with it:

fgets( ap->name, MAX, fp ) ;
nlptr = strrchr ( ap->name, '\n' ) ;
if( nlptr != 0 )
{
    *nlptr = '\0' ;
}
like image 30
Clifford Avatar answered Sep 28 '22 15:09

Clifford