Re: nested structures and initialization
- From: James Kuyper <jameskuyper@xxxxxxxxxxx>
- Date: Wed, 31 Oct 2007 11:39:40 GMT
Sheldon wrote:
Hi,
Can anyone help with this problem with setting up nested structures
and initializing them for use.
I have created several structs and placed them in a super struct that
I will then pass to some functions. I have defined them in the
following manner:
typedef struct trans Transient;
typedef struct sats Satellites;
typedef struct data Data;
typedef struct super Super;
struct data {
float table_10[ROW*COL];
float table_20[ROW*COL];
float table_30[ROW*COL];
float table_40[ROW*COL];
float table_50[ROW*COL];
float table_60[ROW*COL];
float procent_amsu;
};
Why do you define 6 separate on-dimensional tables, rather than a single table with a leading dimension of 6? I suspect it will simplify the code that uses this structure.
I would also recommend combining those typedefs with the corresponding struct declarations:
typedef struct data {....} Data;
I find that easier to understand; YMMV.
struct trans {
char operationalfile[MAXSTR_LENGTH];
char tunedfile[MAXSTR_LENGTH];
char radarfile[MAXSTR_LENGTH];
float amsu_flag[ARRAYSIZE];
float radar[ARRAYSIZE];
float pcpn1[ARRAYSIZE];
float pcpn2[ARRAYSIZE];
float pcpn3[ARRAYSIZE];
};
Same comment about the pcpn family.
struct sats {
Data *pN18;
Data *pN17;
Data *pN16;
Data *pN15;
Data *pM02;
};
struct super {
Transient *TR;
Satellites *Sp;
Satellites *Su;
Satellites *Au;
Satellites *Wi;
};
Super* InitStruct(void);
Now when I try to intialize the structure I get a bunch of errors. The
InitStruct functions looks like this:
int main() {
Super *sptr;
/* initializing the super structure */
sptr = InitStruct();
if (sptr == NULL) {
fprintf(stderr,"Failed to initialize nested structure!\n");
exit(EXIT_FAILURE);
} else {
printf("Structure now initialized!\n");
}
return 1;
}
Super *InitStruct(void) {
That's a bad naming choice. InitSuper would be better. In general, you might have quite a lot of different structures to initialize. In this particular case, you have two of them, which is enough to justify not naming either function "InitStruct".
Super *sptr=NULL;
if(!(sptr=malloc(sizeof(Super)))) {
return NULL;
}
At this point, none of the pointer members of *sptr have been initialized. Any use of the value of those pointers has undefined behavior. You need to allocate memory for each of the pointed at objects. Note: with this data structure you're going to have to make LOTS of separate memory allocations. If any one of those fails, then all of the allocations that succeeded should be free()d. This can get very complicated very fast. I avoid building structures like this, for precisely that reason. Therefore, the solution I use below is not the result of lots of experience with this kind of thing, but it's a lot better than other techniques I've seen used:
bool successful = true;
// Initialize to make sure that we can free() them without worrying
// about whether they have been allocated:
sptr->TR = NULL;
sptr->Sp = NULL;
// Similarly for other pointer members
if(!(sptr->TR = malloc(sizeof Transient)) ||
!(sptr->Sp = malloc(sizeof Satellites)) ||
// Similarly for other pointer members
){
successful = false;
}
....
sptr->TR->amsu_flag={0.0};
The curly brackets are a syntax error in this context. I think you are thinking of initialization syntax, but that doesn't apply to dynamically allocated memory. You'll have to write a loop to initialize that array. You'll be doing a lot of this, so I'd recommend creating a subroutine analogous to memset() which works on floats rather than unsigned char.
If you use calloc() instead of malloc(), or use memset() after malloc(), on many implementations the floats will be properly initialized. That's because floating point formats which use a representation for 0.0 that has all of its bits set to 0 are fairly common. However, that's not guaranteed by the C standard, so you should not use that approach in code that needs to be portable.
At this point, none of the pointer members of sptr->Sp have been initialized. Any attempt to use their current value has undefined behavior. You need to allocate memory for each one, just as I described above for the pointer members of sptr itself. You'll need to do this many times, so I recommend writing as subroutine to handle it. Later on, you'll need to deallocate all of that memory; again, you should use a subroutine. I'll need to refer to those routines down below, so I'll call them InitSatellite() and FreeSatellite(). Note: if the argument passed to FreeSatellite is null, it should return without doing anything, the same way that free() itself does.
Remember to set successful = false if any of the InitSatellite() calls fails.
This code should (with appropriate re-writes) be part of InitSatellite():
....
sptr->Sp->N18->table_10={0.0};....
if(!successful)
{ // Free everything, regardless of whether it's been allocated.
free(sptr->TR);
FreeSatellite(sptr->Sp);
free(sptr->Sp);
// Similarly for other Satellites* members.
free(sptr);
return NULL;
}
return sptr;
// Your original did not appear to include a return statement?
}.
- References:
- nested structures and initialization
- From: Sheldon
- nested structures and initialization
- Prev by Date: Re: nested structures and initialization
- Next by Date: Re: nested structures and initialization
- Previous by thread: Re: nested structures and initialization
- Next by thread: Re: nested structures and initialization
- Index(es):
Relevant Pages
|