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

fwrite/fread problem

0 views
Skip to first unread message

Nico ter Haar

unread,
Sep 17, 2001, 3:31:59 PM9/17/01
to

Hallo,

I've got a structure declared and pointers to it which I
try to write to a file using fwrite as follows:


typedef struct
{
<snipped>
}_OWNER;


typedef _OWNER *_OWNER_PTR;


_OWNER_PTR *OWNER;


fwrite( OWNER,sizeof(_OWNER),1,writeF );


This is not working as reading it back is creating garbage.
I must have got the pointers etc. mixed up, but how to unwind
them?

Or is there an easier way to save and reload ?
thanks


--
RISC OS Foundation member Acorn RiscPC-SA200
RISC OS Select member MicroDigital Omega
http://www.neptune.demon.nl/
mailto:ni...@neptune.demon.nl

Alex Waugh

unread,
Sep 17, 2001, 4:03:37 PM9/17/01
to
In message <ant17195...@neptune.demon.nl>

Nico ter Haar <ni...@neptune.demon.nl> wrote:

>
> Hallo,
>
> I've got a structure declared and pointers to it which I
> try to write to a file using fwrite as follows:
>
>
> typedef struct
> {
> <snipped>
> }_OWNER;
>
>
> typedef _OWNER *_OWNER_PTR;
>
>
> _OWNER_PTR *OWNER;

^
You probably want to get rid of this, as currently you are creating a
pointer to a pointer to a structure.
IMHO it would be easier to get rid of the second typedef and just use
_OWNER *OWNER;

> fwrite( OWNER,sizeof(_OWNER),1,writeF );
>
>
> This is not working as reading it back is creating garbage.
> I must have got the pointers etc. mixed up, but how to unwind
> them?
>
> Or is there an easier way to save and reload ?

This is probably the simplest way, but not the best.
It is non-portable; structures may have different amounts of padding
between members on different platforms.
It also causes problems if you ever want to change the structure, as any
existing files saved witht the old structure will no longer work.
The best way is to write each member of the structure to the file
separately, preferably in a textual format.

HTH

Alex

--
Alex Waugh Electronics student ajw...@ecs.soton.ac.uk

RISC OS freeware from http://www.ecs.soton.ac.uk/~ajw498/

John Kortink

unread,
Sep 17, 2001, 4:15:56 PM9/17/01
to
On Mon, 17 Sep 2001 21:31:59 +0200, Nico ter Haar
<ni...@neptune.demon.nl> wrote:

>
>Hallo,
>
>I've got a structure declared and pointers to it which I
>try to write to a file using fwrite as follows:
>
>
>typedef struct
>{
> <snipped>
>}_OWNER;
>
>
>typedef _OWNER *_OWNER_PTR;
>
>
>_OWNER_PTR *OWNER;
>
>
>fwrite( OWNER,sizeof(_OWNER),1,writeF );
>
>
>This is not working as reading it back is creating garbage.

That's because what you're writing to the file is not
an instantiation of the struct, but something which
happens to be at the unknown address contained by
pointer-to-pointer-to-_OWNER OWNER. Even if OWNER
was initialised, it would not point to an _OWNER
(size of the struct) but to a pointer-to-_OWNER
(size usually four).

>I must have got the pointers etc. mixed up, but how to unwind
>them?

The type of OWNER is **_OWNER, not *_OWNER as probably
intended. So, first, you want :

_OWNER_PTR OWNER;

not

_OWNER_PTR *OWNER;

Even then, OWNER now points to an _OWNER (not a pointer-to-_OWNER)
but an actual _OWNER doesn't exist and hasn't been assigned to.
You should create an instantiation of _OWNER to be able to put
something in it. And then save it.

E.g., add :

_OWNER an_owner; /* An actual object */
OWNER = &an_owner; /* Link the pointer to it */
an_owner.something = other; /* Put something in it */

>Or is there an easier way to save and reload ?

Something like :

/* The type */

typedef struct
{
<snipped>
}
_OWNER;

/* An instantiation of the type */

_OWNER an_owner;

/* Assignments to the instatiation */

an_owner.something = other;

/* Write the instantiation to file */

fwrite(&an_owner,sizeof(_OWNER),1,writeF);

/* To read it back from file lateron */

fread(&an_owner,sizeof(_OWNER),1,readF);


John Kortink

Email : kor...@inter.nl.net
Homepage : http://www.inter.nl.net/users/J.Kortink

ViewFinder, the high performance graphics card for RISC PC's :
http://www.windfall.nl

Ralph Corderoy

unread,
Sep 17, 2001, 4:33:16 PM9/17/01
to
Hi Nico,

> I've got a structure declared and pointers to it which I
> try to write to a file using fwrite as follows:

OK, here's an example with more `normal' case conventions. You should
be able to work from that.

#include <stdio.h>

typedef struct {
int person_id;
int date_obtained;
} owner;

int main(int argc, char *argv[])
{
owner o;

o.person_id = 0x42;
o.date_obtained = 0xbeef;
fprintf(stderr, "%u\n", fwrite(&o, sizeof o, 1, stdout));

return 0;
}

Here's it running.

% ./j | od -x
1
0000000 0042 0000 beef 0000
0000010

The `1' is the return value from fwrite. The next two lines are the
output of fwrite.

Cheers,


Ralph.

Ralph Corderoy

unread,
Sep 17, 2001, 4:39:04 PM9/17/01
to
Hi again Nico,

> typedef struct
> {
> <snipped>
> }_OWNER;
>
> typedef _OWNER *_OWNER_PTR;
>
> _OWNER_PTR *OWNER;

So owner is a pointer to an owner_ptr which is a pointer to an owner.
That's probably one to many levels of indirection.

> fwrite( OWNER,sizeof(_OWNER),1,writeF );


Ralph.

André Timmermans

unread,
Sep 18, 2001, 3:23:47 AM9/18/01
to
John Kortink wrote:
>
> /* Write the instantiation to file */
>
> fwrite(&an_owner,sizeof(_OWNER),1,writeF);
>
> /* To read it back from file lateron */
>
> fread(&an_owner,sizeof(_OWNER),1,readF);

Even better use sizeof(an_owner) instead of sizeof(_OWNER)

<pedantic>
Much overlooked is the fact that the parameter of sizeof isn't
restricted
to data types, you can use the name of variables in which case the
compiler returns the size of the variable's datatype.

For example:

_OWNER *x;

x is of datatype _OWNER* so sizeof(x) returns the size of the pointer.
*x is of datatype _OWNER so sizeof(*x) returns the size of the _OWNER
struct.

My recommandation is to always use variables instead of datatypes
as parameters to sizeof:
- it allows you change the type of a variable (e.g. from float
to double) without having to update all the releated sizeofs
- you're sure to get the size of the correct datatype (just in case
you thought that the variable was of type xyz when it's actually
of type xyw).
- if you mistake a variable of a given datatype as a pointer of the
given datatype sizeof(*x) is sure to report an error unless the
datatype in question is itself a pointer.
</pedantic>

André

Ralph Corderoy

unread,
Sep 18, 2001, 8:49:09 AM9/18/01
to
Hi Andre,

> My recommandation is to always use variables instead of datatypes as
> parameters to sizeof:

Agreed, if you've got one handy. Also, parenthesis aren't required
with variables. See my other post in this thread or a C grammar.


Ralph.

Ian Bannister

unread,
Sep 17, 2001, 3:15:27 PM9/17/01
to
In article <ant17195...@neptune.demon.nl>, Nico ter Haar

<ni...@neptune.demon.nl> wrote:
>
>
> Hallo,
>
> I've got a structure declared and pointers to it which I
> try to write to a file using fwrite as follows:
>
>
> typedef struct
> {
> <snipped>
> }_OWNER;
>
>
> typedef _OWNER *_OWNER_PTR;
>
>
> _OWNER_PTR *OWNER;
>
>
> fwrite( OWNER,sizeof(_OWNER),1,writeF );
>
>
> This is not working as reading it back is creating garbage.
> I must have got the pointers etc. mixed up, but how to unwind
> them?
>
> Or is there an easier way to save and reload ?
> thanks
>

What is the purpose of the second typedef? Doesn't OWNER end up becoming a
pointer to a pointer? ie **_OWNER.
You have created a perfectly good type definer in the first statement. If
you want it to represent real memory there must be a real structure and then
you can pass a pointer to this:-

_OWNER a;
fwrite(&a,sizeof(_OWNER),1,WriteF);

Let me know if I got the wrong end of the stick etc.


--
|-*- Ian Bannister


Nico ter Haar

unread,
Sep 18, 2001, 2:22:05 PM9/18/01
to
In article <d56f93bb...@alexwaugh.com>, Alex Waugh

<URL:mailto:ajw...@ecs.soton.ac.uk> wrote:
> In message <ant17195...@neptune.demon.nl>
> Nico ter Haar <ni...@neptune.demon.nl> wrote:
>
> >
> > Hallo,
> >
> > I've got a structure declared and pointers to it which I
> > try to write to a file using fwrite as follows:
> >
> >
> > typedef struct
> > {
> > <snipped>
> > }_OWNER;
> >
> >
> > typedef _OWNER *_OWNER_PTR;
> >
> >
> > _OWNER_PTR *OWNER;
> ^
> You probably want to get rid of this, as currently you are creating a
> pointer to a pointer to a structure.
> IMHO it would be easier to get rid of the second typedef and just use
> _OWNER *OWNER;
>
Above suggested by more people contributing. And I can see the logic
in it not working, but ..

But then I wouldn't be able to use something like OWNER[ 2 ]->name
or would I. The thing is I have many owners. Now I can just malloc the
pointer all at the same time (not much memory) and then whenever a
new owner is added I can malloc the actual structure.

> > fwrite( OWNER,sizeof(_OWNER),1,writeF );


> > Or is there an easier way to save and reload ?
>
> This is probably the simplest way, but not the best.
> It is non-portable; structures may have different amounts of padding
> between members on different platforms.
> It also causes problems if you ever want to change the structure, as any
> existing files saved witht the old structure will no longer work.
> The best way is to write each member of the structure to the file
> separately, preferably in a textual format.
>

But not using fgets/fprintf I suppose as this does horrible things with
regard to my input/output, something with control terminated and
null terminated strings I think.
I've got my strings from the toolbox-writable fields for instance and this
is causing trouble. I then have to check all strings.


Thanks sofar

Alex Waugh

unread,
Sep 18, 2001, 3:24:13 PM9/18/01
to
In message <ant18180...@neptune.demon.nl>

Nico ter Haar <ni...@neptune.demon.nl> wrote:

> In article <d56f93bb...@alexwaugh.com>, Alex Waugh
> <URL:mailto:ajw...@ecs.soton.ac.uk> wrote:
> > In message <ant17195...@neptune.demon.nl>
> > Nico ter Haar <ni...@neptune.demon.nl> wrote:
> >
> > >
> > > Hallo,
> > >
> > > I've got a structure declared and pointers to it which I
> > > try to write to a file using fwrite as follows:
> > >
> > >
> > > typedef struct
> > > {
> > > <snipped>
> > > }_OWNER;
> > >
> > >
> > > typedef _OWNER *_OWNER_PTR;
> > >
> > >
> > > _OWNER_PTR *OWNER;
> > ^
> > You probably want to get rid of this, as currently you are creating a
> > pointer to a pointer to a structure.
> > IMHO it would be easier to get rid of the second typedef and just use
> > _OWNER *OWNER;
> >
> Above suggested by more people contributing. And I can see the logic
> in it not working, but ..
>
> But then I wouldn't be able to use something like OWNER[ 2 ]->name
> or would I. The thing is I have many owners. Now I can just malloc the
> pointer all at the same time (not much memory) and then whenever a
> new owner is added I can malloc the actual structure.

If you want an array of pointers to OWNER structures, then keep the
typedefs as they were, and alter the fwrite call to something like
fwrite(OWNER[2],sizeof(_OWNER),1,writeF);

> > > fwrite( OWNER,sizeof(_OWNER),1,writeF );
> > > Or is there an easier way to save and reload ?
> >
> > This is probably the simplest way, but not the best.
> > It is non-portable; structures may have different amounts of padding
> > between members on different platforms.
> > It also causes problems if you ever want to change the structure, as any
> > existing files saved witht the old structure will no longer work.
> > The best way is to write each member of the structure to the file
> > separately, preferably in a textual format.
> >
> But not using fgets/fprintf I suppose as this does horrible things with
> regard to my input/output, something with control terminated and
> null terminated strings I think.
> I've got my strings from the toolbox-writable fields for instance and this
> is causing trouble. I then have to check all strings.

If you are ever likely to use strcpy, strlen etc. then the strings will
need to be null terminated anyway, so it is probably worth making sure
that they are null terminated.
If you want to write strings that may not be null terminated then you
can use fwrite(string,stringlen,1,writeF); but you would have to
calculate the length without strlen.

Andreas Dehmel

unread,
Sep 19, 2001, 4:03:56 AM9/19/01
to
Nico ter Haar <ni...@neptune.demon.nl> writes:


>Hallo,

>I've got a structure declared and pointers to it which I
>try to write to a file using fwrite as follows:


>typedef struct
>{
> <snipped>
>}_OWNER;


>typedef _OWNER *_OWNER_PTR;

As others have pointed out I really wouldn't do this. Not just here
but as a general rule: don't define new types for pointers, it's
confusing (as your problems also show), even if you mangle the
type name by adding _PTR; a pointer to a type is just that, not really
a new type. That sort of thing was pretty common on DOS/Windows for
legacy reasons because they had all these eye-watering hacks with
FAR * and normal * due to restrictions of the memory model on older
processors (no longer relevant today anyway). No matter what type name
you choose, personally I find it highly confusing to read code like this:

some_type foo;

foo->member = ...


I also second the comment about not using structures directly for IO,
unless your program is 100% RISC OS specific and you're not planning
to port it to another platform _ever_. Read/write member-by-member --
and if you want real portability, byte-by-byte to sort out endianness
as well: if you write a 16bit value v to a file descriptor fp using
fputc(v&0xff, fp); fputc((v>>8)&0xff, fp);
and read it back in using
v = fgetc(fp) || (fgetc(fp)<<8);
it's portable to all platforms where a character is 1 byte (more or less
all you're like to come in contact with). Please no comments about
optimization, I know using fputc()/fgetc() is inefficient, it's just
to explain the principle.

Andreas
--
--------------------------------------------------------------------
Andreas Dehmel Ceterum censeo
Orleansstr. 34 Microsoft esse delendam.
D-81667 Muenchen (Cato the Much Younger)
deh...@forwiss.tu-muenchen.de
Tel. 089 / 48095-206 http://www.forwiss.tu-muenchen.de/~dehmel

Nico ter Haar

unread,
Sep 19, 2001, 6:16:05 AM9/19/01
to
In article <9o9jhc$6p8$1...@sunsystem5.informatik.tu-muenchen.de>, Andreas Dehmel

<URL:mailto:deh...@Informatik.TU-Muenchen.DE> wrote:
> Nico ter Haar <ni...@neptune.demon.nl> writes:
>
> >typedef struct
> >{
> > <snipped>
> >}_OWNER;
>
>
> >typedef _OWNER *_OWNER_PTR;
>
> As others have pointed out I really wouldn't do this. Not just here
> but as a general rule: don't define new types for pointers, it's
> confusing (as your problems also show), even if you mangle the
> type name by adding _PTR; a pointer to a type is just that, not really
> a new type. That sort of thing was pretty common on DOS/Windows for
> legacy reasons because they had all these eye-watering hacks with
> FAR * and normal * due to restrictions of the memory model on older
> processors (no longer relevant today anyway). No matter what type name
> you choose, personally I find it highly confusing to read code like this:
>
> some_type foo;
> foo->member = ...
>
How would you define multiple occurences of some_type.member without
I thought this was the most logical/economical way ?


>
> I also second the comment about not using structures directly for IO,
> unless your program is 100% RISC OS specific and you're not planning
> to port it to another platform _ever_. Read/write member-by-member --
> and if you want real portability, byte-by-byte to sort out endianness
> as well: if you write a 16bit value v to a file descriptor fp using
> fputc(v&0xff, fp); fputc((v>>8)&0xff, fp);
> and read it back in using
> v = fgetc(fp) || (fgetc(fp)<<8);
> it's portable to all platforms where a character is 1 byte (more or less
> all you're like to come in contact with). Please no comments about
> optimization, I know using fputc()/fgetc() is inefficient, it's just
> to explain the principle.
>

As mentioned before by others in this thread the way I was working
wasn't very logical etc. etc.
Therfore I've now changed to using normal textual output on a
line by line basis. And I think the problem is now solved.

thanks all

0 new messages