Printing the last item of a structure twice

R

Rafael Anschau

Hi, the following program uses some c++, so I hope it´s not off topic.
It reads a structure into a file 3 times, but when I tell it to print
them all, it prints the last one twice. I appreciate any
help on what am I doing to cause this.

Thank you,

Rafael

#include <string.h>
#include <string>
#include<iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
char nf[]="1.tst";
string str="Hello world";
FILE *fp;

if ((fp=fopen(nf,"w+"))==NULL) {
std::cout<<"Erro nao abriu";
int a;
cin>>a;
exit(1);
}
typedef struct endereco {
string rua;
int n;

} ender;

ender meu,teu;

int i;

rewind(fp);
for(i=0;i<3;i++) {
cout<<"Nome da rua:\n";
cin>>meu.rua;
cout<<"Numero do ap:\n";
cin>>meu.n;

fwrite(&meu,sizeof(ender),1,fp);

}

cout<<"Listando\n";

rewind(fp);
while(!feof(fp)) {
fread(&teu,sizeof(ender),1,fp);
cout<<teu.rua<<"\n";
cout<<teu.n<<"\n";
}

int a;
cin>>a;
 
R

RjY

Rafael Anschau posted:
Hi, the following program uses some c++, so I hope it´s not off topic.
It reads a structure into a file 3 times, but when I tell it to print
them all, it prints the last one twice. I appreciate any
help on what am I doing to cause this.
while(!feof(fp)) {
fread(&teu,sizeof(ender),1,fp);
cout<<teu.rua<<"\n";
cout<<teu.n<<"\n";
}

I believe you need to test the return value of fread. Something like:

while (!feof(fp)) {
if (fread(&teu, sizeof(ender), 1, fp) == sizeof(ender)) {
// cout etc.etc.
}
}
 
M

Moi

Hi, the following program uses some c++, so I hope it´s not off topic.
It reads a structure into a file 3 times, but when I tell it to print
them all, it prints the last one twice. I appreciate any help on what am
I doing to cause this.
while(!feof(fp)) {

BTW: your program seems C++ to me.

AvK
 
R

Rafael Anschau

"Why not ask C++ questions in comp.lang.c++? "

Because the only c++ thing there is the cout<<var, cin>>var which are
stupid io commands I thought regular C users could grasp. My fault.

PS:Thanks RjY I will check that.
 
J

jameskuyper

Rafael said:
Hi, the following program uses some c++, so I hope it´s not off topic.

Hoping is nice. But hoping that you have enough money to support your
family doesn't actually give you any money, and hoping that your C++
problem isn't off topic in a C newsgroup doesn't remove any of the
numerous uses of C++ features from your program. Your actual problem
is with the part of the C standard library that is inherited by C++
from C, and is exactly the same problem in both languages, but to
expect C programmers to wade though so much C++ stuff in order to
figure this out is more than you can reasonably hope for. Next time,
post such questions to comp.lang.c++.

....
while(!feof(fp)) {
fread(&teu,sizeof(ender),1,fp);

When a file is newly opened, feof(fp) won't be true, not even if it's
a zero-length file, so there's no point in testing it until after the
first call to fread(). If the call to fread() sets the end-of-file
flag, the best you can hope for is that no data was read into your
structure. This appears to be what happened in your case; you
processed the results of the last fread() call, the one that tried and
failed to read the next record when there were no more records to
read. The structure happened to still have the same values in it from
the previous read, which is why it printed out one more time.

You shouldn't count on the consequences of such a mistake being so
minor. The worst that can happen is that the structure is only
partially filled, or filled in with random contents, in which case any
attempt to use it could backfire. Therefore, you should always check
for failure immediately after reading data, and process the data which
was read in only if the read was successful. A better approach:

while(fread(&teu, sizeof teu, 1, fp) == 1)
{
// process data
}
if(ferr(fp))
{
// error handling
}
// else { end of file was reached }
 
J

jameskuyper

Rafael said:
"Why not ask C++ questions in comp.lang.c++? "

Because the only c++ thing there is the cout<<var, cin>>var which are

The lines where you used those things constitute the bulk of your
code.
You also used these other C++-specific features:
<string>
<iostream>
using namespace std;
string
struct tag without 'struct' keyword.

Nowhere in your code are there more than three consecutive non-blank
lines that are free of C++-specific features (except for the line
where you use _tmain() and _TCHAR, which are neither C nor C++, but
something else entirely).
stupid io commands I thought regular C users could grasp. My fault.

Why would you expect C experts to know details of C++? Some of us do,
most don't, and those of us who do aren't necessarily as good at
understanding those details as people on comp.lang.c++.
 
B

Beej Jorgensen

Rafael Anschau said:
Hi, the following program uses some c++, so I hope it´s not off topic.

Some will likely try to redirect you to a C++ newsgroup, but this is
actually a C problem, IMO.
It reads a structure into a file 3 times, but when I tell it to print
them all, it prints the last one twice.

I'm going to bet that you've assumed that feof() will return true as
soon as you've read up through the last byte of the file. But this is
incorrect; feof() is set once you've read /past/ the end of the file.
[Though I'm having trouble finding the bits of the standard that spell
it out quite so explicitly.]

This is a good time to do some desk checking. Let's say your file has
just one struct in it, so it should print out one struct, right?. Trace
through this one step at a time.
while(!feof(fp)) {
fread(&teu,sizeof(ender),1,fp);
cout<<teu.rua<<"\n";
cout<<teu.n<<"\n";
}

1. EOF? No.

2. Read a record (struct #1)
(EOF remains clear at this time because you haven't yet read _past_
the end of the file--you've only read up to the end.)

3. Print a record (struct #1) <<<<<<<<<<<<<<

4. EOF? No.

5. Read a record (fails, returning 0, because you read off the end)
(You should check the return value of fread() to make sure it has
read the number of items you think it has. In any case, at this
point the EOF flag is set because you've read past the end of the
file.)

6. Print a record (struct #1, again) <<<<<<<<<<<<<<

7. EOF? Yes

So notice that we've printed a record twice even though it's the only
record in the file.

What you want to do is not print those values again if feof() is true.
A couple of relatively clean ways I've seen to do this are:

// using the comma operator, read a record, then, for the while()
// condition, check the status of feof()

while(fread(&teu,sizeof(ender),1,fp), !feof(fp)) {
cout<<teu.rua<<"\n";
cout<<teu.n<<"\n";
}

or, perhaps more clearly:

// print records while fread() returns more than zero items
// (in this case you only asked for 1 item, so it should always
// return either 0 or 1 items.)

while(fread(&teu,sizeof(ender),1,fp) > 0) {
cout<<teu.rua<<"\n";
cout<<teu.n<<"\n";
}

You can also test for more errors by clearing the error flag before the
while() loop with clearerr(), and then testing with ferror() after the
while loop. (Or, in the first case, by adding &&!ferror() to the while
condition.)

-Beej
 
R

Rafael Anschau

Thanks Beej, that was it, a subtle semantic difference. Feof returns
true if eof has been reached
not if the pointer is set to the end of the file.

I just read:

"A stream "reaches the end" of a file not by arriving at the e-o-f
position, but by trying (and failing) to go past that position."

I would have done it differently but it´s not my lib.

Thanks again.

Rafael


Rafael Anschau   said:
Hi, the following program uses some c++, so I hope it´s not off topic.

Some will likely try to redirect you to a C++ newsgroup, but this is
actually a C problem, IMO.
It reads a structure into a file 3 times, but when I tell it to print
them all, it prints the last one twice.

I'm going to bet that you've assumed that feof() will return true as
soon as you've read up through the last byte of the file.  But this is
incorrect; feof() is set once you've read /past/ the end of the file.
[Though I'm having trouble finding the bits of the standard that spell
it out quite so explicitly.]

This is a good time to do some desk checking.  Let's say your file has
just one struct in it, so it should print out one struct, right?.  Trace
through this one step at a time.
       while(!feof(fp)) {
               fread(&teu,sizeof(ender),1,fp);
               cout<<teu.rua<<"\n";
               cout<<teu.n<<"\n";
       }

1. EOF?  No.

2. Read a record (struct #1)
   (EOF remains clear at this time because you haven't yet read _past_
   the end of the file--you've only read up to the end.)

3. Print a record (struct #1) <<<<<<<<<<<<<<

4. EOF?  No.

5. Read a record (fails, returning 0, because you read off the end)
   (You should check the return value of fread() to make sure it has
   read the number of items you think it has.  In any case, at this
   point the EOF flag is set because you've read past the end of the
   file.)

6. Print a record (struct #1, again) <<<<<<<<<<<<<<

7. EOF?  Yes

So notice that we've printed a record twice even though it's the only
record in the file.

What you want to do is not print those values again if feof() is true.
A couple of relatively clean ways I've seen to do this are:

    // using the comma operator, read a record, then, for the while()
    // condition, check the status of feof()

    while(fread(&teu,sizeof(ender),1,fp), !feof(fp)) {
        cout<<teu.rua<<"\n";
        cout<<teu.n<<"\n";
    }

or, perhaps more clearly:

    // print records while fread() returns more than zero items
    // (in this case you only asked for 1 item, so it should always
    // return either 0 or 1 items.)

    while(fread(&teu,sizeof(ender),1,fp) > 0) {
        cout<<teu.rua<<"\n";
        cout<<teu.n<<"\n";
    }

You can also test for more errors by clearing the error flag before the
while() loop with clearerr(), and then testing with ferror() after the
while loop.  (Or, in the first case, by adding &&!ferror() to the while
condition.)

-Beej
 
K

Keith Thompson

Rafael Anschau said:
Hi, the following program uses some c++, so I hope it´s not off topic.
It reads a structure into a file 3 times, but when I tell it to print
them all, it prints the last one twice. I appreciate any
help on what am I doing to cause this.
[...]
while(!feof(fp)) { [...]
}
[...]

See question 12.2 of the comp.lang.c FAQ, <http://www.c-faq.com/>.
 
M

Mark Bluemel

Rafael Anschau said:
Hi, the following program uses some c++, so I hope it´s not off topic..
It reads a structure into a file 3 times, but when I tell it to print
them all, it prints the last one twice. I appreciate any
help on what am I doing to cause this.

[...]>         while(!feof(fp)) {
[...]
        }

[...]

See question 12.2 of the comp.lang.c FAQ, <http://www.c-faq.com/>.

Interestingly, I knew the answer to the OPs problem before I read any
of his code.
 
R

Rafael Anschau

Dear Mr. James The Clown,

Thanks for your presentation, though I hope *you* have enough money
to support yourself as programmer, because you haven´t shown great
talent as an enterteiner. If this doesn´t work out, please don´t try
the circus or customers would leave it more depressed than they got
in.

As many inteligent people here have noticed, the problem is with C,
not the small C++ parts. I just wrote that thing about c++ to be
polite, but it seems that among sharks only sarcasm works. Fortunetely
there are nice people around here who are willing to help more than
create noise and draw atention.

Rafael
 
R

Rafael Anschau

Rafael Anschau said:


That was Kenneth, not James.

So is Jameskyper just the failed clown´s artistic name ?
No, the problem is not with C.


Neither is the problem with C++.

So is the problem with failed clown number two Richard ?
 
J

jameskuyper

Kenneth said:
Assuming, of course, that C++'s feof() behaves the same as C's.

The C++ standard library includes essentially all of the C standard
library by reference, with only a few minor modifications. The
overwhelming majority of C standard library function calls work
exactly the same in C++. The only exceptions:

strchr(), strpbrk(), strrchr(), strstr(), memchr(), are all provided
with two overloads; one with parameters that are pointers to const,
and with a return type that is a pointer to const, and one with
ordinary pointer parameters that returns a the same pointer type. It
is very hard to write C code whose meaning or validity would be
affected by this difference, except by using function pointers.

wchar_t, and, and_eq, bitand, bitor, compl, not_eq, not, or, or_eq,
xor, and xor_eq are all C++ keywords, rather than being typdefed or
#defined in the appropriate standard headers.

The expansion of the NULL macro cannot be an expression with a type of
void*, something that C permits. It can be expression that retrieves
the name of static const variable explicitly initialized by an integer
constant expression with a value of 0, something C would not permit.
However, in practice, there's no good reason for it to be anything
other than '0'.

longjmp() has undefined behavior under certain circumstances in C++,
that can't even occur in C code.
offsetof cannot be applied to certain type of structs that can't even
be defined in C.
The malloc() family is guaranteed to not operate by calling operator
new() or operator delete() (the reverse, however, is permitted); such
a guarantee is meaningless in C code.
exit(), atexit(), and abort() interact with various other C++ features
in ways that are not meaningful in C code.

For the most part, you can read C++ code that uses C standard library
functions, without worrying about any of the above differences.
 
J

jameskuyper

Richard said:
jameskuyper said: ....

By value, surely? Otherwise, to conform to the C++ Standard, C++
implementations would have to change every time the C Standard
changed!

I assume that you're just making a joke, but actually, it's been
argued that this is precisely what the ISO's rules require. According
to the person who argued this point (who knew a great deal more than I
do about ISO rules), when C90 ceased to be the official standard,
having been replaced by the approval of C99, all other references to
the C standard in other standards are automatically considered to
refer to the new standard - even if those references explicitly
specify a particular, older, version of the C standard (as is the case
with the reference to it in the C++ standard)!

Personally, I doubt that this is a workable rule; but it might be what
ISO's rules actually say. Other participants in the same discussion
suggested that this rule may have been written at a time when ISO
dealt primarily with hardware standards (such as standards for the
shapes of screws) rather than software standards. I don't think that
explanation works - I think it would be just as unworkable a rule for
hardware standards.

In my personal opinion, the fact that the C++ standard incorporates a
specific version of the C standard library by reference means that C+
+ implementations shouldn't have to be updated when the C standard is
updated. The C++ standard does, however, say that "All standards are
subject to revision, and parties to agreements based on this
International Standard are encouraged to investigate the possibility
of applying the most recent editions of the standards indicated
below." (1.2p1)
 
J

jameskuyper

Rafael said:
Dear Mr. James The Clown,

Why did you post a message directed at me, as a reply to a message by
Kenneth Brody?
Thanks for your presentation, though I hope *you* have enough money
to support yourself as programmer, ...

I do well enough, though I would definitely be interested in
opportunities to improve my salary, so long as they involve scientific
computer programming, and don't require a security clearance. My
current employer would not be surprised to hear this, since they lost
a recompete on the contract that pays my salary.

....
As many inteligent people here have noticed, the problem is with C,

No, the problem is not with C itself, nor is it with your C code,
since that program contained none. The problem was with the part of
your C++ code that uses standard library functions inherited by C++
from C.

....
polite, but it seems that among sharks only sarcasm works. Fortunetely
there are nice people around here who are willing to help more than
create noise and draw atention.

Well, my answer pointed out precisely the correct problem with your
program, explained in detail why it was wrong, and offered
alternative, simpler code that actually works. I'm sorry if you didn't
find that helpful.
 
R

Richard Bos

RjY said:
Rafael Anschau posted:

I believe you need to test the return value of fread. Something like:

while (!feof(fp)) {
if (fread(&teu, sizeof(ender), 1, fp) == sizeof(ender)) {
// cout etc.etc.
}
}

Of possibly something even more like

while (fread(&teu, sizeof teu, 1, fp) == 1) {
// fread() returns elements read, not bytes read
printf(......);
}

which is quite sufficient and rather better style.

Richard
 
R

Rafael Anschau

A still better style is:

while (fread(&teu, sizeof teu, 1, fp)) {

printf(......);
}

since C considers any non-zero integer to be true, and 0 to be false.
 
R

Rafael Anschau

Thanks James you proved there´s a good side in everyone and I look
forward
to re-tribute your help. I´ll look your posts and will answer if I
know how to.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top