Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

no error by fscanf on reading from output file

34 views
Skip to first unread message

V.Subramanian, India

unread,
Oct 30, 2011, 2:59:44 AM10/30/11
to
This question is for learning purpose only.

Consider the program sample.c :

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main()
{
errno = 0;

FILE *fp = fopen("data.txt", "w");

if (fp == NULL)
{
fprintf(stderr,
"Could not open input file - data.txt\n%s\n",
strerror(errno));

return EXIT_FAILURE;
}

if (fprintf(fp, "test data") < 1)
{
fprintf(stderr,
"could not write message into data.txt\n");

return EXIT_FAILURE;
}

fflush(fp);

int a;
int b;

errno = 0;

// I deliberately try to read from the file
// opened in 'write' mode
if (fscanf(fp, "%d%d", &a, &b) == 2)
{
fprintf(stdout,
"a = %d, b= %d\n",
a,
b);
fflush(stdout);
fclose(fp);
return EXIT_SUCCESS;
}

int err = errno;

if (ferror(fp))
{
fprintf(stderr,
"Error encountered while reading input"
" from file\n%s\n",
strerror(err));
fclose(fp);

return EXIT_FAILURE;
}

fclose(fp);

return EXIT_SUCCESS;
}

In this program I open a file 'data.txt' in 'write' mode.
Subsequently, I write something into this file. Then I read
from this file using 'fscanf'. This operation should fail.
But when I test the error indicator for the stream by
calling 'ferror(fp)', the statements inside the
if (ferror(fp))
{
}
are NOT executed.
Does this mean that error inidcator for the stream is not set
by 'fscanf' ? Isn't the operation 'reading from a file
opened in "write" mode' an error ?

I am unable to understand this.

Kindly explain.

Thanks
V.Subramanian

Ian Collins

unread,
Oct 30, 2011, 3:19:10 AM10/30/11
to
You don't test the return of fscanf. Do so and see what happens.

> {
> fprintf(stdout,
> "a = %d, b= %d\n",
> a,
> b);
> fflush(stdout);
> fclose(fp);
> return EXIT_SUCCESS;
> }
>
> int err = errno;
>
> if (ferror(fp))
> {
> fprintf(stderr,
> "Error encountered while reading input"
> " from file\n%s\n",
> strerror(err));
> fclose(fp);
>
> return EXIT_FAILURE;
> }
>
> fclose(fp);
>
> return EXIT_SUCCESS;
> }
>
> In this program I open a file 'data.txt' in 'write' mode.
> Subsequently, I write something into this file. Then I read
> from this file using 'fscanf'. This operation should fail.

But to fail to check!

> But when I test the error indicator for the stream by
> calling 'ferror(fp)', the statements inside the
> if (ferror(fp))
> {
> }
> are NOT executed.
> Does this mean that error inidcator for the stream is not set
> by 'fscanf' ? Isn't the operation 'reading from a file
> opened in "write" mode' an error ?

No, because the FILE* argument isn't a valid input stream. There's
nothing wrong with the stream, you are just using it wrong.

> I am unable to understand this.

Try opening the stream "r+" and then you will see an error condition
occur on the stream.

--
Ian Collins

V.Subramanian, India

unread,
Oct 30, 2011, 3:01:26 AM10/30/11
to
I forgot to add to the OP that I compiled this program under RedHat
Linux with gcc 3.4.3 as
gcc -std=c99 -pedantic -Wall -Wextra sample.c

There is no warning or error.

Ike Naar

unread,
Oct 30, 2011, 4:18:18 AM10/30/11
to
On 2011-10-30, Ian Collins <ian-...@hotmail.com> wrote:
> On 10/30/11 07:59 PM, V.Subramanian, India wrote:
>> if (fscanf(fp, "%d%d",&a,&b) == 2)
>
> You don't test the return of fscanf. Do so and see what happens.

He does; he compares the return of fscanf with 2.

Ian Collins

unread,
Oct 30, 2011, 4:23:25 AM10/30/11
to
Yes he does, but he does nothing if the test fails.

--
Ian Collins

Ike Naar

unread,
Oct 30, 2011, 4:39:09 AM10/30/11
to
On 2011-10-30, V.Subramanian, India <subraman...@yahoo.com> wrote:
> // opened in 'write' mode
> if (fscanf(fp, "%d%d", &a, &b) == 2)
> {
> fprintf(stdout,
> "a = %d, b= %d\n",
> a,
> b);
> fflush(stdout);
> fclose(fp);
> return EXIT_SUCCESS;
> }
>
> [snip]
>
> In this program I open a file 'data.txt' in 'write' mode.
> Subsequently, I write something into this file. Then I read
> from this file using 'fscanf'. This operation should fail.

fscanf does fail (this can be detected by observing that it returns -1).
But fscanf does not read anything from fp (it isn't allowed to
because fp is not in 'read' mode), nothing happens to
the state of fp.

> But when I test the error indicator for the stream by
> calling 'ferror(fp)', the statements inside the
> if (ferror(fp))
> {
> }
> are NOT executed.
> Does this mean that error inidcator for the stream is not set
> by 'fscanf' ? Isn't the operation 'reading from a file
> opened in "write" mode' an error ?

The operation never happes, the stream is not touched.

Eric Sosman

unread,
Oct 30, 2011, 8:11:25 AM10/30/11
to
Perhaps your newsreader has lopped off part of the O.P.'s code.
In the version I see, the "equals two" case goes down one path and
the "else" does something entirely different. Lightly edited:

> if (fscanf(fp, "%d%d", &a, &b) == 2) {
> fprintf(stdout, "a = %d, b= %d\n", a, b);
> fflush(stdout);
> fclose(fp);
> return EXIT_SUCCESS;
> }
> int err = errno;
> if (ferror(fp)) {
> fprintf(stderr, "Error encountered while reading input"
> " from file\n%s\n", strerror(err));
> fclose(fp);
> return EXIT_FAILURE;
> }
> fclose(fp);
> return EXIT_SUCCESS;

--
Eric Sosman
eso...@ieee-dot-org.invalid

Ian Collins

unread,
Oct 30, 2011, 2:38:03 PM10/30/11
to
On 10/31/11 01:11 AM, Eric Sosman wrote:
> On 10/30/2011 4:23 AM, Ian Collins wrote:
>> On 10/30/11 09:18 PM, Ike Naar wrote:
>>> On 2011-10-30, Ian Collins<ian-...@hotmail.com> wrote:
>>>> On 10/30/11 07:59 PM, V.Subramanian, India wrote:
>>>>> if (fscanf(fp, "%d%d",&a,&b) == 2)
>>>>
>>>> You don't test the return of fscanf. Do so and see what happens.
>>>
>>> He does; he compares the return of fscanf with 2.
>>
>> Yes he does, but he does nothing if the test fails.
>
> Perhaps your newsreader has lopped off part of the O.P.'s code.
> In the version I see, the "equals two" case goes down one path and
> the "else" does something entirely different. Lightly edited:

Entirely different in the sense that it doesn't check why fscanf failed.

> > if (fscanf(fp, "%d%d",&a,&b) == 2) {
> > fprintf(stdout, "a = %d, b= %d\n", a, b);
> > fflush(stdout);
> > fclose(fp);
> > return EXIT_SUCCESS;
> > }
> > int err = errno;
> > if (ferror(fp)) {
> > fprintf(stderr, "Error encountered while reading input"
> > " from file\n%s\n", strerror(err));
> > fclose(fp);
> > return EXIT_FAILURE;
> > }
> > fclose(fp);
> > return EXIT_SUCCESS;
>


--
Ian Collins

Ben Bacarisse

unread,
Oct 30, 2011, 3:40:03 PM10/30/11
to
Ian Collins <ian-...@hotmail.com> writes:

> On 10/31/11 01:11 AM, Eric Sosman wrote:
>> On 10/30/2011 4:23 AM, Ian Collins wrote:
>>> On 10/30/11 09:18 PM, Ike Naar wrote:
>>>> On 2011-10-30, Ian Collins<ian-...@hotmail.com> wrote:
>>>>> On 10/30/11 07:59 PM, V.Subramanian, India wrote:
>>>>>> if (fscanf(fp, "%d%d",&a,&b) == 2)
>>>>>
>>>>> You don't test the return of fscanf. Do so and see what happens.
>>>>
>>>> He does; he compares the return of fscanf with 2.
>>>
>>> Yes he does, but he does nothing if the test fails.
>>
>> Perhaps your newsreader has lopped off part of the O.P.'s code.
>> In the version I see, the "equals two" case goes down one path and
>> the "else" does something entirely different. Lightly edited:
>
> Entirely different in the sense that it doesn't check why fscanf
> failed.

I think it does -- at least it tries to. The code fails because fp is
an output stream, and all tests to see why fscanf failed will be useless
on an output stream. The pattern used, though, is reasonable: test for
success (that fscanf reads the number of items required) and then test
for errors on the stream and for EOF.

The only thing that could be added would be to save the return value and
report how many items matched or failed to match. I tend to do this
because it simplifies the EOF test, but that is a small matter of style.

>> > if (fscanf(fp, "%d%d",&a,&b) == 2) {
>> > fprintf(stdout, "a = %d, b= %d\n", a, b);
>> > fflush(stdout);
>> > fclose(fp);
>> > return EXIT_SUCCESS;
>> > }
>> > int err = errno;
>> > if (ferror(fp)) {
>> > fprintf(stderr, "Error encountered while reading input"
>> > " from file\n%s\n", strerror(err));
>> > fclose(fp);
>> > return EXIT_FAILURE;
>> > }
>> > fclose(fp);

It might short-circuit the discussion if you say what it is you think
the OP should be testing for.

>> > return EXIT_SUCCESS;

--
Ben.

Ian Collins

unread,
Oct 30, 2011, 3:50:49 PM10/30/11
to
On 10/31/11 08:40 AM, Ben Bacarisse wrote:
> Ian Collins<ian-...@hotmail.com> writes:
>
>> On 10/31/11 01:11 AM, Eric Sosman wrote:
>>> On 10/30/2011 4:23 AM, Ian Collins wrote:
>>>> On 10/30/11 09:18 PM, Ike Naar wrote:
>>>>> On 2011-10-30, Ian Collins<ian-...@hotmail.com> wrote:
>>>>>> On 10/30/11 07:59 PM, V.Subramanian, India wrote:
>>>>>>> if (fscanf(fp, "%d%d",&a,&b) == 2)
>>>>>>
>>>>>> You don't test the return of fscanf. Do so and see what happens.
>>>>>
>>>>> He does; he compares the return of fscanf with 2.
>>>>
>>>> Yes he does, but he does nothing if the test fails.
>>>
>>> Perhaps your newsreader has lopped off part of the O.P.'s code.
>>> In the version I see, the "equals two" case goes down one path and
>>> the "else" does something entirely different. Lightly edited:
>>
>> Entirely different in the sense that it doesn't check why fscanf
>> failed.
>
> I think it does -- at least it tries to. The code fails because fp is
> an output stream, and all tests to see why fscanf failed will be useless
> on an output stream. The pattern used, though, is reasonable: test for
> success (that fscanf reads the number of items required) and then test
> for errors on the stream and for EOF.
>
> The only thing that could be added would be to save the return value and
> report how many items matched or failed to match. I tend to do this
> because it simplifies the EOF test, but that is a small matter of style.

I guess I'm used to the POSIX behaviour where fscanf will set errno on
failure. In this case, EOF will be returned and errno will be set to
EBADF to indicate the file has not been opened for reading.

--
Ian Collins

Carlo Dapor

unread,
Oct 30, 2011, 10:16:50 PM10/30/11
to
On Oct 30, 7:59 am, "V.Subramanian, India"
Hello V. Subramanian


I also learned a few things, thanks to your posting.
The results are from Mac OS X 10.6.8, they may not apply to RedHat
Linux.

Allow me to point out some observations.

1. fscanf's behaviour

What I take away is that fscanf(3) does not set errno, whether the
call succeeds or not.
Modifying your original source code, errno is always -234 below.
Calling ferror(fp) after fscanf has no effect.

2. Format used

You assumed that two numbers are adjacent ("%d%d").
This is rather misleading.
Say the input were 193.
Should that be read as "1" followed by "93" (case 1), or "19" followed
by "3" (case 2).
The solution is to specify "%1d%2d" for case 1 and "%2d%1d" for case
2.
Another solution is to separate the numbers with a white-space, like
below.

3. Writing and reading to/from the same file

As pointed out, you must create the file with "r+" or "w+".

4. File position

After writing to the file, you are at the end of the file.
If you want to read from it, you must re-position the reader to the
beginning, with fseek or rewind.
Or you could call fclose(fp) followed by fopen(...).

Here's the code:


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>


int
main (int argc, char *argv[])
{
int a, b, count = -1, status = EXIT_SUCCESS;
FILE *fp = fopen ("data.txt", "w+");

fprintf (fp, "23 57"); // valid input
//fprintf (fp, "no number"); // invalid input

if (0 != errno) {
fprintf (stderr, "Could not write data: '%s'\n", strerror
(errno));

return EXIT_FAILURE;
}

// re-set the position to the beginning
rewind (fp);

// unfortunately, errno is not set, whether fscanf succeeds or
not!
errno = -234;
count = fscanf (fp, "%d %d", &a, &b);

if (2 == count) {
fprintf (stdout, "a=%d, b=%d, errno=%d\n", a, b, errno);
}
else {
fprintf (stderr, "Expected 2 tokens, got %d; errno=%d\n",
count, errno);
status = EXIT_FAILURE;
}

fclose (fp);
return status;
}


Regards,
--
Carlo

Ian Collins

unread,
Oct 30, 2011, 10:50:41 PM10/30/11
to
On 10/31/11 03:16 PM, Carlo Dapor wrote:
>
> I also learned a few things, thanks to your posting.
> The results are from Mac OS X 10.6.8, they may not apply to RedHat
> Linux.
>
> Allow me to point out some observations.
>
> 1. fscanf's behaviour
>
> What I take away is that fscanf(3) does not set errno, whether the
> call succeeds or not.

It isn't required to set errno by the C standard, but it is on a POSIX
compliant system. So it should set errno on both Linux and OSX.

--
Ian Collins

V.Subramanian, India

unread,
Oct 31, 2011, 1:55:52 AM10/31/11
to
On Oct 30, 12:19 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> > if (fscanf(fp, "%d%d",&a,&b) == 2)
>
> You don't test the return of fscanf. Do so and see what happens.
>
>
>
> > {
> > fprintf(stdout,
> > "a = %d, b= %d\n",
> > a,
> > b);
> > fflush(stdout);
> > fclose(fp);
> > return EXIT_SUCCESS;
> > }
>
> > int err = errno;
>
> > if (ferror(fp))
> > {
> > fprintf(stderr,
> > "Error encountered while reading input"
> > " from file\n%s\n",
> > strerror(err));
> > fclose(fp);
>
> > return EXIT_FAILURE;
> > }
>
> > fclose(fp);
>
> > return EXIT_SUCCESS;
> > }
>
> > In this program I open a file 'data.txt' in 'write' mode.
> > Subsequently, I write something into this file. Then I read
> > from this file using 'fscanf'. This operation should fail.
>
> But to fail to check!
>
> > But when I test the error indicator for the stream by
> > calling 'ferror(fp)', the statements inside the
> > if (ferror(fp))
> > {
> > }
> > are NOT executed.
> > Does this mean that error inidcator for the stream is not set
> > by 'fscanf' ? Isn't the operation 'reading from a file
> > opened in "write" mode' an error ?
>
> No, because the FILE* argument isn't a valid input stream. There's
> nothing wrong with the stream, you are just using it wrong.
>
> > I am unable to understand this.
>
> Try opening the stream "r+" and then you will see an error condition
> occur on the stream.
>
> --
> Ian Collins


Does 'fscanf' set the error indicator of a stream on error while
reading the stream ? If so, ferror(fp) should succeed and the contents
inside 'if (ferror(fp)) {...}' should be executed. Kindly provide a
code for the above scenario. I am unable to come up with this code. I
tried the following:

In the original program mentioned in the OP, I just modified the mode
to "r+" and also "w+" without any other code change; but in both cases
the ferror(fp) part was not executed.

I am compiling the program with the following options:
gcc -std=c99 -pedantic -Wall -Wextra sample.c

I thought, the above options use Standard C and not POSIX. Is it
correct ?

Please help me understand under what circumstances, if at all, fscanf
sets the error indicator for a stream. If it doesn't, I NEVER have to
do the check 'if (ferror(fp)) {...}' after a call to fscanf. Am I
correct ?.

Thanks
V.Subramanian

Ike Naar

unread,
Oct 31, 2011, 3:02:54 AM10/31/11
to
On 2011-10-31, Carlo Dapor <cat...@gmail.com> wrote:
> 2. Format used
>
> You assumed that two numbers are adjacent ("%d%d").

No. "%d%d" is a valid format for reading two separated integers;
it will skip initial whitespace before the first integer, read the
first integer, skip whitespace beteeen the first and the second
integer, and read the second integer.

> This is rather misleading.
> Say the input were 193.
> Should that be read as "1" followed by "93" (case 1), or "19" followed
> by "3" (case 2).

Neither; it will read the first number as 193 (assuming the next
character after "193" does not extend that number to a larger valid
integer). Then any separating whitespace is skipped, and a second
integer will be read. If there is no second integer in the input
stream, fscanf will still read the first integer as 193, then return
1 to indicate that only one item was read.

> The solution is to specify "%1d%2d" for case 1 and "%2d%1d" for case
> 2.

In general you do not know beforehand how large the numbers in the
input stream will be, so you cannot predict the number of digits
to read for the first number. Separating the numbers by whitespace
is often the better way.

Alan Curry

unread,
Oct 31, 2011, 3:14:25 AM10/31/11
to
In article <721e72aa-54ae-4a90...@u37g2000prh.googlegroups.com>,
V.Subramanian, India <subraman...@yahoo.com> wrote:
>
>Does 'fscanf' set the error indicator of a stream on error while
>reading the stream ? If so, ferror(fp) should succeed and the contents
>inside 'if (ferror(fp)) {...}' should be executed. Kindly provide a
>code for the above scenario. I am unable to come up with this code. I
>tried the following:

It's nice that you want to test your error handling code path, but injecting
an error that will be reported by ferror() is not easy. ferror() is the
indicator of I/O errors, which usually have a cause that exists outside your
program, like a hard disk with bad sectors.

Check the return value of fscanf first. If it returned EOF, then you can call
ferror() to distinguish between a normal end-of-file condition and an I/O
error. In all other cases, ferror() won't be useful.

--
Alan Curry

Ian Collins

unread,
Oct 31, 2011, 3:56:03 AM10/31/11
to
It's unfortunate that without the additional POSIX requirement, there
isn't a standard way to detect the error condition (invalid operation on
the stream) in the original example. I guess the best option is to call
feof() on the stream, at least that way you will be able to
differentiate between an end of file condition and an error.

--
Ian Collins

Nick Keighley

unread,
Oct 31, 2011, 4:35:46 AM10/31/11
to
On Oct 31, 5:55 am, "V.Subramanian, India"
<subramanian10...@yahoo.com> wrote:
> On Oct 30, 12:19 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> > On 10/30/11 07:59 PM, V.Subramanian, India wrote:

<snip>

> > No, because the FILE* argument isn't a valid input stream.  There's
> > nothing wrong with the stream, you are just using it wrong.
>
> > > I am unable to understand this.
>
> > Try opening the stream "r+" and then you will see an error condition
> > occur on the stream.
>
> > --
> > Ian Collins

it's usual to snip sigs (the bit after a "-- ")

<snip>

> I am compiling the program with the following options:
> gcc -std=c99 -pedantic -Wall -Wextra sample.c
>
> I thought, the above options use Standard C and not POSIX. Is it
> correct ?

To The Best Of My Knowledge flags to gcc specify the behaviour of gcc
(ie. of the compiler), whilst fscanf() is part of the library. gcc is
actually independent of the library and uses whatever is provided by
the system (there are semi-portable versions of the c library). hence
on a Posix compliant system you get a Posix compiant C library.

Note the C standard only specifies which standdard functions /must/
set errno. It doesn't say that others can't. (pedant point: I'm sure
there are a few library functions that must not set errno).

Ben Bacarisse

unread,
Oct 31, 2011, 11:43:49 AM10/31/11
to
pac...@kosh.dhis.org (Alan Curry) writes:

> In article <721e72aa-54ae-4a90...@u37g2000prh.googlegroups.com>,
> V.Subramanian, India <subraman...@yahoo.com> wrote:
>>
>>Does 'fscanf' set the error indicator of a stream on error while
>>reading the stream ? If so, ferror(fp) should succeed and the contents
>>inside 'if (ferror(fp)) {...}' should be executed. Kindly provide a
>>code for the above scenario. I am unable to come up with this code. I
>>tried the following:
>
> It's nice that you want to test your error handling code path, but injecting
> an error that will be reported by ferror() is not easy.

True. I do it with freopen sometimes in conjunction with fwide. It's
not at all portable, but where it works it's great to be able cause IO
fails at any desired test point.

To break an input stream, re-open it with mode "w", and vice-versa. If
the stream is read-write, re-open it read-write but set the stream to be
wide oriented (or byte oriented if you are really using wide stream).

<snip>
--
Ben.

Keith Thompson

unread,
Oct 31, 2011, 4:46:15 PM10/31/11
to
Nick Keighley <nick_keigh...@hotmail.com> writes:
[...]
> Note the C standard only specifies which standdard functions /must/
> set errno. It doesn't say that others can't. (pedant point: I'm sure
> there are a few library functions that must not set errno).
[...]

Actually, I don't think there are any.

C99 7.5p3:

The value of errno is zero at program startup, but is never set
to zero by any library function. The value of errno may be set
to nonzero by a library function call whether or not there is
an error, provided the use of errno is not documented in the
description of the function in this International Standard.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
0 new messages