Pointers to structs - help!

J

Jim

Ok, I'm having 'fun' with pointers to structures.

I've got some code that looks something like this:

====================
typedef struct
{
unsigned long *clno, *lastHistoryRecord;
} aRecord;

....
....

void main()
{
....
....
theRecord aRecord;

theRecord.clno = (unsigned long*) malloc(sizeof(long));
theRecord.lastHistoryRecord = (unsigned long*) malloc(sizeof(long));

getArecord( infile, &theRecord, recordNumber );

printf( "%ld %ld\n", theRecord.clno, theRecord.lastHistoryRecord );
....
....
}


int getArecord( FILE *infile, aRecord *thisRecord, long recordNumber )
{
....
....
fread( &thisRecord->lastHistoryRecord, 1L, sizeof(long), infile );
fread( &thisRecord->clno, 1L, sizeof( long ) * 1, infile );
....
....
return result;
}

====================

(large chunks of code snipped for brevity)


Now, it _seems_ to do as I expect. Let's say that I run this and get:

1000 1234

as a result. If I change the printf line to say:

printf( "%ld %ld\n", theRecord.clno-1, theRecord.lastHistoryRecord );

then I get

996 1234. I would have expected 999. So I'm obviously doing something very,
very stupid somewhere[0]. Could someone enlighten me? FWIW I've also tried
--theRecord.clno and (theRecord.clno)-1 but they both do the same.

Many thanks. Sorry if this is a really, really obvious one..!

Jim
[0] apart from not checking the mallocs for errors
 
M

Mark Bluemel

Jim said:
typedef struct
{
unsigned long *clno, *lastHistoryRecord;
} aRecord;

So structures of this type contain pointers to unsigned longs - why not
just longs?
theRecord aRecord;

theRecord.clno = (unsigned long*) malloc(sizeof(long));
theRecord.lastHistoryRecord = (unsigned long*) malloc(sizeof(long));

That makes some sense, though I'd rather you at least said
"malloc(sizeof(unsigned long))", and dropped the cast (not helpful).

The c.l.c preferred form would be :-

theRecord.clno = malloc(sizeof(*theRecord.clno));

etc...
fread( &thisRecord->lastHistoryRecord, 1L, sizeof(long), infile );
> fread( &thisRecord->clno, 1L, sizeof( long ) * 1, infile );

Here you pass fread() the _addresses_ of the pointers to long. So the
data read from the file is put there. Either you need to change this
code to remove the & characters, or change the structure to contain un
> printf( "%ld %ld\n", theRecord.clno, theRecord.lastHistoryRecord );

This passes printf() two pointers and tells it it has two longs - this
is clearly wrong.
1000 1234

But you get away with it.

as a result. If I change the printf line to say:

printf( "%ld %ld\n", theRecord.clno-1, theRecord.lastHistoryRecord );

then I get

996 1234.

theRecord.clno is a pointer to unsigned long. Subtracting 1 from it
moves it "back" (for some value of back) by sizeof(unsigned long). Again
you pass printf() two pointers but tell it that they are longs, again
you "get away" with it...

Your code would work acceptably simply by amending the structure to
contain unsigned longs, rather than pointers to them, and removing the
mallocs...
 
J

Jim

theRecord.clno is a pointer to unsigned long. Subtracting 1 from it
moves it "back" (for some value of back) by sizeof(unsigned long). Again
you pass printf() two pointers but tell it that they are longs, again
you "get away" with it...

Barely, it would seem.
Your code would work acceptably simply by amending the structure to
contain unsigned longs, rather than pointers to them, and removing the
mallocs...

Done and it now works as expected. Many thanks, and I'll try to get this
into my head in future.

Jim
 
B

Barry Schwarz

Ok, I'm having 'fun' with pointers to structures.

I've got some code that looks something like this:

====================
typedef struct
{
unsigned long *clno, *lastHistoryRecord;
} aRecord;

This defines a **type** known as aRecord.
...
...

void main()

main returns int.
{
...
...
theRecord aRecord;

This is a syntax error. There is no type known as theRecord. Perhaps
you would like to show us your real code. Use cut and paste. Do not
attempt to retype it.
theRecord.clno = (unsigned long*) malloc(sizeof(long));

Don't cast the return from malloc. The only thing it accomplishes is
preventing the compiler from issuing a diagnostic which you would
really want to see.

It is always desirable that the operand of sizeof match the type of
the object being pointed to. long and unsigned long may have the same
size but it is a better style. To this end, the frequent
recommendation here is
theRecord.clno = malloc(sizeof *theRecord.clno);
which will still be correct if you later need to change the type of
clno.
theRecord.lastHistoryRecord = (unsigned long*) malloc(sizeof(long));

getArecord( infile, &theRecord, recordNumber );

printf( "%ld %ld\n", theRecord.clno, theRecord.lastHistoryRecord );

This is undefined behavior. Neither the second nor third arguments
match the type of the respective format specification. Both are
pointers where the format requires a long.

If you meant to print the pointer values (unlikely), use %p and cast
the arguments to void*. If you meant to print the values pointed to,
then apply the dereference operator (*) to both arguments.
...
...
}


int getArecord( FILE *infile, aRecord *thisRecord, long recordNumber )

You did know the correct type name.
{
...
...
fread( &thisRecord->lastHistoryRecord, 1L, sizeof(long), infile );

This will work only if the data in infile was produced on a system
which stores long values EXACTLY the same as the system you are
running this program on.
fread( &thisRecord->clno, 1L, sizeof( long ) * 1, infile );
...
...
return result;
}

====================

(large chunks of code snipped for brevity)


Now, it _seems_ to do as I expect. Let's say that I run this and get:

1000 1234

By very bad luck, the undefined behavior printed pointer values that
very much resemble integers.
as a result. If I change the printf line to say:

printf( "%ld %ld\n", theRecord.clno-1, theRecord.lastHistoryRecord );

then I get

996 1234. I would have expected 999. So I'm obviously doing something very,

By equally bad luck, sizeof(long) on your system is 4 and the pointer
arithmetic resulted in another value that looks like an integer.
very stupid somewhere[0]. Could someone enlighten me? FWIW I've also tried
--theRecord.clno and (theRecord.clno)-1 but they both do the same.

Many thanks. Sorry if this is a really, really obvious one..!

You want *theRecord.clno-1. This dereferences the pointer to obtain
the long value and subtracts one from that value, not from the
pointer.
Jim
[0] apart from not checking the mallocs for errors


Remove del for email
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,017
Latest member
GreenAcreCBDGummiesReview

Latest Threads

Top