nested struct that grow in some cases

S

Sheldon

Hi,

I have a unique case where I need an array of structs that grows and
within this array is another struct that grows in some cases. I'm
having trouble allocating memory. Since I have never done this before,
I'm sure it's a rookie mistake but I cannot seem to find it. Can
someone render some assistance please?

struct Fpos {
grib_handle *h;
char level[MAX_VAL_LEN];
};

struct Parameter {
double *lvlpress;
double *geomethgt;
double *ab_array;
double *pottemp;
int nlev;
size_t size;
char parameter[MAX_VAL_LEN];
unsigned char **GribNameValues;
struct Fpos **filepos;
} **Darray;


Darray = (struct Parameter **)realloc(Darray,(num + 1)*sizeof(struct
Parameter *));
/* allocate memory for one struct Parameter */
Darray[num] = (struct Parameter *)smalloc(sizeof(struct Parameter));
/* same as above but for the nested struct */
Darrray[num]->filepos = (struct Fpos **)realloc(filepos,(lvlnum +
1)*sizeof(struct Fpos *));
Darrray[num]->filepos[lvlnum] = (struct Fpos *)smalloc(sizeof(struct
Fpos));

When I compile, I get an error saying that filepos is not declared and
is new.

How should this be done properly?

/M
 
M

MisterE

When I compile, I get an error saying that filepos is not declared and
is new.

How should this be done properly?

You need to post more code. You don't declare Darray at all, you only set
Darray as a tag.
So Darray = (struct ..... line should be telling you that Darray is not
declared.
Filepos is not declared either:
Darrray[num]->filepos = (struct Fpos **)realloc(filepos, <--- not declared
variable

post your code properly not just cut lines
 
B

Ben Bacarisse

Sheldon said:
I have a unique case where I need an array of structs that grows and
within this array is another struct that grows in some cases. I'm
having trouble allocating memory. Since I have never done this before,
I'm sure it's a rookie mistake but I cannot seem to find it. Can
someone render some assistance please?

You have a few typos. Did you post actual code?
struct Fpos {
grib_handle *h;
char level[MAX_VAL_LEN];
};

struct Parameter {
double *lvlpress;
double *geomethgt;
double *ab_array;
double *pottemp;
int nlev;
size_t size;
char parameter[MAX_VAL_LEN];
unsigned char **GribNameValues;
struct Fpos **filepos;
} **Darray;


Darray = (struct Parameter **)realloc(Darray,(num + 1)*sizeof(struct
Parameter *));

Beware. This is wrong unless Darray has been set to NULL (or points
previously allocated memory).

Life will be simpler is you use the comp.lang.c standard idiom:

ptr = malloc(how_many * sizeof *ptr);
/* allocate memory for one struct Parameter */
Darray[num] = (struct Parameter *)smalloc(sizeof(struct Parameter));
/* same as above but for the nested struct */
Darrray[num]->filepos = (struct Fpos **)realloc(filepos,(lvlnum +
1)*sizeof(struct Fpos *));

Both Darrray (note three 'r's) and filepos (the one after realloc) are
new undeclared names here. One is a typo, but the other is just
wrong. You probably meant ... realloc(Darray[num]->filepos, ...
Darrray[num]->filepos[lvlnum] = (struct Fpos *)smalloc(sizeof(struct
Fpos));

Three 'r's again and smalloc is an odd name.
When I compile, I get an error saying that filepos is not declared and
is new.

How should this be done properly?

Do you really need pointers of arrays of pointers for both Darray and
the internal filepos? Dynamic arrays are often just represented by
pointers to the first element.
 
B

Ben Bacarisse

MisterE said:
You need to post more code. You don't declare Darray at all, you only set
Darray as a tag.

No, he declared it. The struct tag is "Parameter".
 
D

David Thompson

Hi,

I have a unique case where I need an array of structs that grows and
within this array is another struct that grows in some cases. I'm

Not actually within. I'd say under or subordinate to each element.
having trouble allocating memory. Since I have never done this before,
I'm sure it's a rookie mistake but I cannot seem to find it. Can
someone render some assistance please?

struct Fpos {
grib_handle *h;
char level[MAX_VAL_LEN];
};

struct Parameter {
double *lvlpress;
double *geomethgt;
double *ab_array;
double *pottemp;
int nlev;
size_t size;
char parameter[MAX_VAL_LEN];
unsigned char **GribNameValues;
struct Fpos **filepos;
} **Darray;


Darray = (struct Parameter **)realloc(Darray,(num + 1)*sizeof(struct
Parameter *));
/* allocate memory for one struct Parameter */
Darray[num] = (struct Parameter *)smalloc(sizeof(struct Parameter));

These are valid assuming that Darray is initialized to a null pointer
and num to zero, which will happen automatically if they are defined
at file scope (or otherwise with static duration). But you should
check for allocation failure and handle it in some reasonable fashion;
to do that it may be better to save realloc's return in a temporary
and check it first before putting it into Darray. And you don't need
to cast the return of malloc et al., if they are properly declared by
#include'ing <stdlib.h>, which they must be.

However, if the number of struct Parameter pointers gets large, on
most implementations it will be inefficient to realloc up by 1 each
time, because it will at least sometimes have to copy quadratically
increasing amounts of data. You might want to do something a little
more complicated like:
unsigned long numalloc /* = 0 *(/, numused /* = 0 */;
struct Parameter ** Darray /* = NULL */;
....
if( numused == /* or >= to be defensive */ numalloc ){
struct Parameter **temp = realloc (Darray,
(numalloc=numalloc*3/2+1) * sizeof (struct Parameter *) );
/* or sizeof *temp, which is equivalent and safe
and easier to maintain, hence clc-preferred */
/* personally I usually start with a smallish nonzero number,
and grow by *2, but that's a little bit more to write */
if( temp == NULL ) HANDLE ERROR;
Darray = temp; /* successfully grew */
}
/* now there's at least Darray[0..numused] and often more */
Darray[numused] = smalloc (sizeof *Darray[numused]);
/* unless smalloc() already handled allocation failure: */
if( Darray[numused] == NULL ) HANDLE ERROR;
/* same as above but for the nested struct */
Darrray[num]->filepos = (struct Fpos **)realloc(filepos,(lvlnum +
1)*sizeof(struct Fpos *));
Darrray[num]->filepos[lvlnum] = (struct Fpos *)smalloc(sizeof(struct
Fpos));

As others have noted, the second filepos here is a variable not a
struct member. But if you make it the struct member that might not be
right either. Did smalloc() initialize the space containing it
suitably? If not, trying to realloc it is Undefined Behavior.
Note that initializing the space to all-zero-bits isn't guaranteed to
make the pointer null, although on _most_ systems it does work.
And smalloc() sounds like a general-purpose routine that doesn't know
about the contents of what it allocates and in particular where
pointers are (or can be).

Plus, your lvlnum is questionable. It can be a separate single
variable only if all Darray elements have the same 'size' of
Darray->filepos at all times, and your code as shown doesn't do
that. If you want say Darray[1]->filepos to grow separately from
Darray[0]->filepos, you need a separate counter in (or mapped
one-to-one to) each struct Parameter. You do have .nlev already, whose
name sounds like it might be intended for this. It similarly must be
initialized to zero, but for an integer type (not a pointer)
initializing to all-bits-zero (if smalloc() does that) is OK.

If you want them all to grow in sync, you need different logic. E.g.:
- allocate Darray to M pointers and each of those M pointers to a
struct Parameter with .filepos null (empty); you can do this using
one-at-a-time logic like the above, or all (or batches) at once
- (then) allocate each Darray [0..M-1] ->filepos to N pointers and set
each of those Darray [0..M-1] ->filepos [0..N-1] to a struct Fpos.
Again you can do these one-at-a-time, in which case you can nest the
loops either way (for each filepos within in Darray or vice versa), or
batched in which case the allocations of the pointer space must loop
over Darray[] (first) but the elements can then nest either way but
can be merged with the pointer allocation only if Darray-major.

Other logics are possible. You'd have to explain more about what you
want to do with (i.e. put into) the resulting data structure.
When I compile, I get an error saying that filepos is not declared and
is new.

How should this be done properly?

/M
- formerly david.thompson1 || achar(64) || worldnet.att.net
 

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,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top