accessing dynamically allocated structures 
Author Message
 accessing dynamically allocated structures

Hello,

I'm trying to access the memory I dynamically allocated for a struct
type I defined. I actually malloc'd enough to hold a few structs.

How do you go about using or accessing the memory you've dynamically
allocated for a struct type? My pointer arithmetic dumps core! :o(

I've broken part of my code down to a simpler program that illustrates
what I'm trying to do. The code seg faults when it enters the loop on
the second pass and tries to snprintf() to what I think would be the
next available piece of memory for the next struct.

Hope this code post isn't too much... I just thought it would better
explain what I'm trying to do.

/*
 *  dstruct.c - test dynamic memory alloc and access for struct
 */

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

#define MAX_ACCTS       10
#define MAX_STR         64

/* account type to hold each account's properties */
typedef struct {
         char    szName[MAX_STR+1];    /* account name */
         char    szAddr[MAX_STR+1];    /* account address */

Quote:
} Account;

int main( int argc, char *argv[] )
{
int i;                          /* loop counter */
Account *paAcct;        /* pointer to 1st account */
Account *paTemp;        /* temp. pointer to other accounts */

/* allocate enough memory for MAX_ACCTS (structs) */
paAcct = malloc( MAX_ACCTS * sizeof(Account) );
if ( paAcct == NULL ) {
    fprintf( stderr, "malloc() failed for accounts\n" );
    return 1;

Quote:
}

/* initialize malloc'd memory */
memset( (Account *)paAcct, 0, MAX_ACCTS*sizeof(Account) );

/* set temp. account pointer to new memory */
paTemp = paAcct;

/* add account data */
for ( i = 0; i < MAX_ACCTS; i++ ) {
    /* copy account data; second pass SEG FAULTS!!! :o( */
    snprintf( paTemp->szName, MAX_STR, "%s %i", "Account", i+1 );
    snprintf( paTemp->szAddr, MAX_STR, "%s %i", "Address", i+1 );
    /* set temp. pointer to next struct in memory for next pass */
    paTemp = paTemp + sizeof(Account);

Quote:
}

free( paAcct );

return 0;

Quote:
}

What is recommended as the best, most portable approach for handling this
type of dynamic memory access for structures? An old C/C++ book I have
recommends only using the increment and decrement operators for pointer
arithmetic. Is this true? It sure seems that way! ;o)

On another note... is the malloc() OK? I had a typecast in there before,
but I took it out after reading some other posts. It was:
paAcct = (Account *) malloc( MAX_ACCTS * sizeof(Account) );
I'm confused on the (void *) aspect. I thought it was considered good
practice and recommended to typecast a (void *) for anything... since it
can represent any type. Is this true with memset() as well, which I believe
takes a (void *) too?

Thanks for your time,
-Eric



Mon, 11 Apr 2005 22:44:04 GMT  
 accessing dynamically allocated structures


Quote:
> Hello,

> I'm trying to access the memory I dynamically allocated for a struct
> type I defined. I actually malloc'd enough to hold a few structs.

> How do you go about using or accessing the memory you've dynamically
> allocated for a struct type? My pointer arithmetic dumps core! :o(

> I've broken part of my code down to a simpler program that illustrates
> what I'm trying to do. The code seg faults when it enters the loop on
> the second pass and tries to snprintf() to what I think would be the
> next available piece of memory for the next struct.

> Hope this code post isn't too much... I just thought it would better
> explain what I'm trying to do.

> /*
>  *  dstruct.c - test dynamic memory alloc and access for struct
>  */

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

> #define MAX_ACCTS       10
> #define MAX_STR         64

> /* account type to hold each account's properties */
> typedef struct {
>          char    szName[MAX_STR+1];    /* account name */
>          char    szAddr[MAX_STR+1];    /* account address */
> } Account;

> int main( int argc, char *argv[] )
> {
> int i;            /* loop counter */
> Account *paAcct;    /* pointer to 1st account */
> Account *paTemp;    /* temp. pointer to other accounts */

> /* allocate enough memory for MAX_ACCTS (structs) */
> paAcct = malloc( MAX_ACCTS * sizeof(Account) );
> if ( paAcct == NULL ) {
>     fprintf( stderr, "malloc() failed for accounts\n" );
>     return 1;
> }

> /* initialize malloc'd memory */
> memset( (Account *)paAcct, 0, MAX_ACCTS*sizeof(Account) );

> /* set temp. account pointer to new memory */
> paTemp = paAcct;

> /* add account data */
> for ( i = 0; i < MAX_ACCTS; i++ ) {
>     /* copy account data; second pass SEG FAULTS!!! :o( */
>     snprintf( paTemp->szName, MAX_STR, "%s %i", "Account", i+1 );
>     snprintf( paTemp->szAddr, MAX_STR, "%s %i", "Address", i+1 );
>     /* set temp. pointer to next struct in memory for next pass */
>     paTemp = paTemp + sizeof(Account);

Here's your problem.  A paTemp is a pointer to an Account, and so when you
add N to the pointer, it steps to the N'th Account after it is currently
pointing, and not to the N'th byte.  So, as written, the above statement
steps to (at least) 130 Accounts, and not to the next one.  What you want
is:

   paTemp = paTemp + 1;

Quote:
> }

> free( paAcct );

> return 0;
> }

> What is recommended as the best, most portable approach for handling this
> type of dynamic memory access for structures? An old C/C++ book I have
> recommends only using the increment and decrement operators for pointer
> arithmetic. Is this true? It sure seems that way! ;o)

IMHO, I would drop the pointer arithmetic, and use array notation, as in:

for ( i = 0; i < MAX_ACCTS; i++ ) {
    paTemp = &paAcct[i];
    snprintf( paTemp->szName, MAX_STR, "%s %i", "Account", i+1 );
    snprintf( paTemp->szAddr, MAX_STR, "%s %i", "Address", i+1 );

Quote:
}

There is a use for pointer arithmetic, but (again, IMHO) it doesn't come up
as often as you may think, and is best avoided when unnecessary.

Quote:

> On another note... is the malloc() OK? I had a typecast in there before,
> but I took it out after reading some other posts. It was:
> paAcct = (Account *) malloc( MAX_ACCTS * sizeof(Account) );
> I'm confused on the (void *) aspect. I thought it was considered good
> practice and recommended to typecast a (void *) for anything... since it
> can represent any type. Is this true with memset() as well, which I
believe
> takes a (void *) too?

IMHO, the malloc line you have is fine, you should lose the typecast on the
memset call.  It's good practice to avoid typecasts whenever possible -- a
typecast on a pointer type is usually a way of telling the compiler "I know
what I am doing", and when reviewing code, should be high on your list to
check whether in fact the programmer is telling the truth.  If you have
extraneous ones, the ones that need double-checking are obscured.

--
poncho



Mon, 11 Apr 2005 23:04:11 GMT  
 accessing dynamically allocated structures

Quote:

> How do you go about using or accessing the memory you've dynamically
> allocated for a struct type? My pointer arithmetic dumps core! :o(
> for ( i = 0; i < MAX_ACCTS; i++ ) {
>     /* copy account data; second pass SEG FAULTS!!! :o( */
>     snprintf( paTemp->szName, MAX_STR, "%s %i", "Account", i+1 );
>     snprintf( paTemp->szAddr, MAX_STR, "%s %i", "Address", i+1 );
>     /* set temp. pointer to next struct in memory for next pass */
>     paTemp = paTemp + sizeof(Account);  }

A pointer knows the size of the elements to which it points.  To get
to the next pointer, you should just increment paTemp by one, rather
than by sizeof(Account);

That is:

        /* Point to the next account (correct) */
        paTemp++;

        /* Point to sizeof(Account) accounts after the current account */
        paTemp += sizeof(Account); /* probably not what you want */



Tue, 12 Apr 2005 00:37:19 GMT  
 accessing dynamically allocated structures

Quote:

>>     /* set temp. pointer to next struct in memory for next pass */
>>     paTemp = paTemp + sizeof(Account);

> Here's your problem.  A paTemp is a pointer to an Account, and so when
> you add N to the pointer, it steps to the N'th Account after it is
> currently pointing, and not to the N'th byte.  So, as written, the above
> statement steps to (at least) 130 Accounts, and not to the next one.
> What you want is:

>    paTemp = paTemp + 1;

Many thanks for your help! When I think in terms of pointers, I guess I've
always thought of "an address" in my mind. I've also always thought in
terms of "a byte address" as well, which to me equals one.

So how should I modify my understanding of pointers? Is the following
correct...?
A pointer is a variable in memory which holds a logical address. Depending
on the size of the type the pointer is pointing to, the expression 'pointer
+ 1' will add the necessary number of bytes to make pointer equal to the
correct logical address. So, I don't have to bother with sizeof().

Quote:

> A pointer knows the size of the elements to which it points.  To get
> to the next pointer, you should just increment paTemp by one, rather
> than by sizeof(Account);

> That is:
> /* Point to the next account (correct) */
> paTemp++;

I got Paul's message right before I was going to post above... it helps
very much!

Hmmm, I was making it harder... not fun.  ;o)

Thanks all,
-Eric



Tue, 12 Apr 2005 00:46:10 GMT  
 accessing dynamically allocated structures

Quote:

> Hello,

> I'm trying to access the memory I dynamically allocated for a struct
> type I defined. I actually malloc'd enough to hold a few structs.

> How do you go about using or accessing the memory you've dynamically
> allocated for a struct type? My pointer arithmetic dumps core! :o(

(parts of post and code snipped)

Quote:
> int main( int argc, char *argv[] )
> {
> int i;                     /* loop counter */
> Account *paAcct;           /* pointer to 1st account */
> Account *paTemp;           /* temp. pointer to other accounts */

> /* allocate enough memory for MAX_ACCTS (structs) */
> paAcct = malloc( MAX_ACCTS * sizeof(Account) );

> /* set temp. account pointer to new memory */
> paTemp = paAcct;

> /* add account data */
> for ( i = 0; i < MAX_ACCTS; i++ ) {
>     /* copy account data; second pass SEG FAULTS!!! :o( */
>     snprintf( paTemp->szName, MAX_STR, "%s %i", "Account", i+1 );
>     snprintf( paTemp->szAddr, MAX_STR, "%s %i", "Address", i+1 );
>     /* set temp. pointer to next struct in memory for next pass */
>     paTemp = paTemp + sizeof(Account);
> }

There's two ways you can approach this. You're using pointer math,
which
is fine, except you made a simple mistake. Instead of
    paTemp = paTemp + sizeof(Account);
you actually need
    paTemp = paTemp + 1;
or, more simply,
    paTemp++;

When you increment a pointer by 1, the compiler increments the
address by the correct number of bytes...that is, if your structure is
12
bytes in size, and you do "paTemp++;", then the value of the pointer
will be
incremented by 12. It saves you from needing to know the size of the
structure
and details about how everything's stored in memory.

The second approach requires understanding that pointers and arrays
are
equivalent in C. If you declare an array "int x[50];", then the type
of x is
actually "int *"...it's a pointer to the beginning of the array.
That's exactly
what you're doing here, except you're allocating the array
dynamically.

So, you could rewrite your loop as
/* add account data */
for ( i = 0; i < MAX_ACCTS; i++ ) {
    /* copy account data */
    snprintf( paAcct[i].szName, MAX_STR, "%s %i", "Account", i+1 );
    snprintf( paAcct[i].szAddr, MAX_STR, "%s %i", "Address", i+1 );

Quote:
}

It's shorter and easier to read, and it does exactly the same thing.
You can get rid of the paTemp variable entirely, at least in the code
you posted.

Quote:
> On another note... is the malloc() OK? I had a typecast in there before,
> but I took it out after reading some other posts. It was:
> paAcct = (Account *) malloc( MAX_ACCTS * sizeof(Account) );

I'd personally leave the typecast in. The compiler will do exactly the
same
thing, but it makes the code a little clearer. Also, the cast is
required in C++, so if you ever need to compile the code on a C++
compiler in the future, the typecast will make your life less painful.

- Darryl



Tue, 12 Apr 2005 05:52:18 GMT  
 accessing dynamically allocated structures

Quote:

> [...]
> How do you go about using or accessing the memory you've dynamically
> allocated for a struct type? My pointer arithmetic dumps core! :o(

    I see only one serious error, plus a couple oportunities
for stylistic improvement.  Heavily snipped:

Quote:
> int main( int argc, char *argv[] )
> {
> int i;                          /* loop counter */
> Account *paAcct;        /* pointer to 1st account */
> Account *paTemp;        /* temp. pointer to other accounts */

> /* allocate enough memory for MAX_ACCTS (structs) */
> paAcct = malloc( MAX_ACCTS * sizeof(Account) );

    Room for improvement: As written, you need to remember
that `paAcct' points to `Account' objects.  In this small
program that's not too difficult, but what if you also had
`Acct' and `Delinquent_Account' and a few other object types
roaming about?  It's easy to get the pointer on the left
mismatched with the `sizeof' on the right ...  Even if
you never make such errors, consider someone else reading
the code: to verify its correctness he's got to find the
declaration of `paAcct' (which might be in some header
file far, far away) and make sure things match.  If instead
you write

        paAcct = malloc( MAX_ACCTS * sizeof *paAcct );

... the mismatch error becomes impossible, and all questions
about correctness can be answered just by looking at this
one line by itself.  (Well, not quite: if `paAcct' is a
`double' the line is wrong -- but you won't need to figure
this out for yourself since the compiler will shriek at you.)

Quote:
> if ( paAcct == NULL ) {
>     fprintf( stderr, "malloc() failed for accounts\n" );
>     return 1;

    Room for improvement: Return `EXIT_FAILURE' instead.

Quote:
> }

> /* initialize malloc'd memory */
> memset( (Account *)paAcct, 0, MAX_ACCTS*sizeof(Account) );

    Room for improvement: Same `sizeof' comment as above.

    Room for improvement: `paAcct' is already an `Account*',
so there's no need to convert it to what it already is.  You
don't write `i = (int)0;', do you?

    Room for improvement: If you want dynamic memory that's
cleared to all-bits-zero, consider using calloc() instead of
malloc() plus memset().

Quote:
> /* set temp. account pointer to new memory */
> paTemp = paAcct;
> [...]
>     /* set temp. pointer to next struct in memory for next pass */
>     paTemp = paTemp + sizeof(Account);

    The actual error: Pointer arithmetic is done in units of the
pointed-to element, not in units of bytes (unless the pointed-to
thing is byte-sized, of course).  If you've got a pointer to a
Thing, you get to the next Thing by adding 1, not by adding the
number of bytes in a Thing.

Quote:
> What is recommended as the best, most portable approach for handling this
> type of dynamic memory access for structures? An old C/C++ book I have
> recommends only using the increment and decrement operators for pointer
> arithmetic. Is this true? It sure seems that way! ;o)

    It's very common to find yourself stepping forward or backward
through an array, visiting each element in turn, and the increment
and decrement operators are well-suited to this.  But there are lots
of other visitation patterns, too: binary search jumps into the middle
and then takes smaller and smaller leaps left and right, heapsort
starts at the beginning and takes progressively longer leaps rightward,
hashing schemes use steps that may depend on the data stored, and so on.
The increment and decrement operators aren't much help with these more
intricate patterns.

Quote:
> On another note... is the malloc() OK? I had a typecast in there before,
> but I took it out after reading some other posts. It was:
> paAcct = (Account *) malloc( MAX_ACCTS * sizeof(Account) );
> I'm confused on the (void *) aspect. I thought it was considered good
> practice and recommended to typecast a (void *) for anything... since it
> can represent any type. Is this true with memset() as well, which I believe
> takes a (void *) too?

    In C, the conversion between `void*' and any other object pointer
type occurs automatically, and doesn't need to be spelled out with
an explicit cast.  (In C++, so I'm told, different rules prevail.)
The usual C wisdom is to omit the cast because it can hide some
kinds of errors and can even introduce new ones.  Just about the
only exception is when you're passing a pointer as an argument to a
variadic function:

        printf ("%p\n", paAcct);

is incorrect, and should instead be written

        printf ("%p\n", (void*)paAcct);

Some people feel it's good practice always to cast pointers when
passing them as function arguments, perhaps because if you form
such a habit you'll be less likely to omit the casts in the few
instances when they're actually needed.  Personally, I subscribe
to the "less is more" philosophy, and leave 'em out.

--



Tue, 12 Apr 2005 06:13:35 GMT  
 accessing dynamically allocated structures

Quote:



>> Hello,

>> I'm trying to access the memory I dynamically allocated for a struct
>> type I defined. I actually malloc'd enough to hold a few structs.

>> How do you go about using or accessing the memory you've dynamically
>> allocated for a struct type? My pointer arithmetic dumps core! :o(

>> I've broken part of my code down to a simpler program that illustrates
>> what I'm trying to do. The code seg faults when it enters the loop on
>> the second pass and tries to snprintf() to what I think would be the
>> next available piece of memory for the next struct.

>> Hope this code post isn't too much... I just thought it would better
>> explain what I'm trying to do.

>> /*
>>  *  dstruct.c - test dynamic memory alloc and access for struct
>>  */

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

>> #define MAX_ACCTS       10
>> #define MAX_STR         64

>> /* account type to hold each account's properties */
>> typedef struct {
>>          char    szName[MAX_STR+1];    /* account name */
>>          char    szAddr[MAX_STR+1];    /* account address */
>> } Account;

>> int main( int argc, char *argv[] )
>> {
>> int i;            /* loop counter */
>> Account *paAcct;    /* pointer to 1st account */
>> Account *paTemp;    /* temp. pointer to other accounts */

>> /* allocate enough memory for MAX_ACCTS (structs) */
>> paAcct = malloc( MAX_ACCTS * sizeof(Account) );
>> if ( paAcct == NULL ) {
>>     fprintf( stderr, "malloc() failed for accounts\n" );
>>     return 1;
>> }

>> /* initialize malloc'd memory */
>> memset( (Account *)paAcct, 0, MAX_ACCTS*sizeof(Account) );

>> /* set temp. account pointer to new memory */
>> paTemp = paAcct;

>> /* add account data */
>> for ( i = 0; i < MAX_ACCTS; i++ ) {
>>     /* copy account data; second pass SEG FAULTS!!! :o( */
>>     snprintf( paTemp->szName, MAX_STR, "%s %i", "Account", i+1 );
>>     snprintf( paTemp->szAddr, MAX_STR, "%s %i", "Address", i+1 );
>>     /* set temp. pointer to next struct in memory for next pass */
>>     paTemp = paTemp + sizeof(Account);
> Here's your problem.  A paTemp is a pointer to an Account, and so when you
> add N to the pointer, it steps to the N'th Account after it is currently
> pointing, and not to the N'th byte.  So, as written, the above statement
> steps to (at least) 130 Accounts, and not to the next one.  What you want
> is:

>   paTemp = paTemp + 1;

>> }

>> free( paAcct );

>> return 0;
>> }

>> What is recommended as the best, most portable approach for handling this
>> type of dynamic memory access for structures? An old C/C++ book I have
>> recommends only using the increment and decrement operators for pointer
>> arithmetic. Is this true? It sure seems that way! ;o)
> IMHO, I would drop the pointer arithmetic, and use array notation, as in:

> for ( i = 0; i < MAX_ACCTS; i++ ) {
>    paTemp = &paAcct[i];
>    snprintf( paTemp->szName, MAX_STR, "%s %i", "Account", i+1 );
>    snprintf( paTemp->szAddr, MAX_STR, "%s %i", "Address", i+1 );
> }

Or even get rid of paTemp entirely, and use:

    snprintf( paAcct[i].szName, MAX_STR, "%s %i", "Account", i+1 );
    snprintf( paAcct[i].szAddr, MAX_STR, "%s %i", "Account", i+1 );

thereby treating paAcct as a "dynamically allocated array".

        - Kevin.



Wed, 13 Apr 2005 13:56:34 GMT  
 accessing dynamically allocated structures

Quote:


>>>     /* set temp. pointer to next struct in memory for next pass */
>>>     paTemp = paTemp + sizeof(Account);

>> Here's your problem.  A paTemp is a pointer to an Account, and so when
>> you add N to the pointer, it steps to the N'th Account after it is
>> currently pointing, and not to the N'th byte.  So, as written, the above
>> statement steps to (at least) 130 Accounts, and not to the next one.
>> What you want is:

>>    paTemp = paTemp + 1;

> Many thanks for your help! When I think in terms of pointers, I guess I've
> always thought of "an address" in my mind. I've also always thought in
> terms of "a byte address" as well, which to me equals one.

> So how should I modify my understanding of pointers? Is the following
> correct...?
> A pointer is a variable in memory which holds a logical address. Depending
> on the size of the type the pointer is pointing to, the expression 'pointer
> + 1' will add the necessary number of bytes to make pointer equal to the
> correct logical address. So, I don't have to bother with sizeof().

Yep. (ptr + i) is exactly the same as &ptr[i].

        - Kevin.



Wed, 13 Apr 2005 13:57:45 GMT  
 
 [ 8 post ] 

 Relevant Pages 

1. nested dynamically allocated structures

2. Assign NULL to a dynamically allocated set of structures

3. Dynamically allocating a structure array

4. Passing Member of Dynamically Allocated Structure to Function

5. how to dynamically allocate a structure containing pointer type structures?

6. Dynamically allocated CByteArrays in a loop

7. How to pass dynamically allocated arrays??

8. Dynamically allocate a character array

9. dynamically allocating strings

10. dynamically allocating strings

11. Dynamically allocated array of pointers and their usage.

12. Dynamically allocating mem for 2-D char array

 

 
Powered by phpBB® Forum Software