How to write own function to allocation a set of structures?

M

Martin De Kauwe

Hi,

I currently allocate a series of structures...

in the .h file

typedef struct {
FILE *in_fp;
etc....
} control_struct;

then in the main func:

control_struct *ctrl;
if ((ctrl = malloc(sizeof(control_struct))) == NULL) {
fprintf(stderr, "control structure: Not allocated enough memory
\n");
exit(EXIT_FAILURE);
}

I would like to write my own generic function to take the malloc
section to tidy up the code (as I have a number of structures to
allocate), i.e. so instead in the main I would have something like

allocate_structure(&ctrl);

and

void allocate_structure(structure *s) {
if ((s = malloc(sizeof(structure))) == NULL) {
fprintf(stderr, "Structure: Not allocated enough memory\n");
exit(EXIT_FAILURE);
}
}

But I am not sure how to pass the structure when it is unallocated,
i.e. how to set up the function declarations.

Any assistance would be very helpful

thanks.
 
I

Ian Collins

Hi,

I currently allocate a series of structures...

in the .h file

typedef struct {
FILE *in_fp;
etc....
} control_struct;

then in the main func:

control_struct *ctrl;
if ((ctrl = malloc(sizeof(control_struct))) == NULL) {
fprintf(stderr, "control structure: Not allocated enough memory
\n");
exit(EXIT_FAILURE);
}

I would like to write my own generic function to take the malloc
section to tidy up the code (as I have a number of structures to
allocate), i.e. so instead in the main I would have something like

allocate_structure(&ctrl);

and

void allocate_structure(structure *s) {
if ((s = malloc(sizeof(structure))) == NULL) {
fprintf(stderr, "Structure: Not allocated enough memory\n");
exit(EXIT_FAILURE);
}
}

But I am not sure how to pass the structure when it is unallocated,
i.e. how to set up the function declarations.

Either return the value allocated, or pass a pointer to the pointer:

structure* allocate_structure()
{
structure* s = malloc(sizeof *s);
//error check
return s;
}

Or

void allocate_structure( structure** s )
{
*s = malloc(sizeof *s);
//error check
}
 
B

Barry Schwarz

Is your function going to allocate space for exactly one object of the
same structure type each time? If so, Ian's suggestions should work
just fine.

If it is a variable quantity but always the same structure type, then
pass the quantity as a parameter, use it in the call to malloc, and
still follow Ian's suggestions.

If the structure type also varies, then something like

void * alloc_struct(size_t struct_size, int quantity)
{
void *ptr = malloc(struct_size * quantity);
if (!ptr)
{
/* your error logic here */
}
return ptr;
}

could be called with code like

struct1_ptr = alloc_struct(sizeof(struct1), 5);
struct2_ptr = alloc_struct(sizeof(struct2), 8);
 
M

Martin De Kauwe

Sorry I am not sure I quite sure I followed that. I do have variable
length structures, e.g. some are X parameters long, some are a set of
controlling flags. I tried implementing the first example, but I am
clearly misunderstanding how to do this.

in the .h file

typedef struct {
FILE *ifp;
int num_days;
etc...
} control_struct;

void allocate_structure(structure **);

in the .c file

int main(int argc, char **argv)
{
/* Allocate all structures */
control_struct *ctrl;
allocate_structure(&ctrl);
etc...

void allocate_structure(structure **s)
{
if ((*s = malloc(sizeof(*s))) == NULL) {
fprintf(stderr, "some msg\n");
exit(EXIT_FAILURE);
}

}

it says it doesn't know what 'structure' is when it compiles. I must
be misunderstanding as this is what I didn't get, i.e. how to pass the
structure, what you call it when you pass it to the function.
 
I

Ian Collins

Sorry I am not sure I quite sure I followed that. I do have variable
length structures, e.g. some are X parameters long, some are a set of
controlling flags. I tried implementing the first example, but I am
clearly misunderstanding how to do this.

in the .h file

typedef struct {
FILE *ifp;
int num_days;
etc...
} control_struct;

void allocate_structure(structure **);

in the .c file

int main(int argc, char **argv)
{
/* Allocate all structures */
control_struct *ctrl;
allocate_structure(&ctrl);
etc...

void allocate_structure(structure **s)
{
if ((*s = malloc(sizeof(*s))) == NULL) {
fprintf(stderr, "some msg\n");
exit(EXIT_FAILURE);
}

}

it says it doesn't know what 'structure' is when it compiles. I must
be misunderstanding as this is what I didn't get, i.e. how to pass the
structure, what you call it when you pass it to the function.

It sounds like you are looking for C++ style templates, which C lacks.

In C, you would have to resort to a macro. Something like

#define ALLOCATE_STRUCTURE( s ) \
if ((s = malloc(sizeof(*s))) == NULL) { \
fprintf(stderr, "some msg\n"); \
exit(EXIT_FAILURE); } \
 
M

Martin De Kauwe

I have never used c++ so i am not sure what a c++ style template is,
but perhaps it is because I have been using a lot of python recently.
What you suggested works fine. Ideally what I was trying to do was
move all the structure allocation into a function so the main function
read a little cleaner. Your suggestion certainly helps, thanks.
 
B

Ben Bacarisse

Martin De Kauwe said:
Sorry I am not sure I quite sure I followed that. I do have variable
length structures, e.g. some are X parameters long, some are a set of
controlling flags. I tried implementing the first example, but I am
clearly misunderstanding how to do this.

in the .h file

typedef struct {
FILE *ifp;
int num_days;
etc...
} control_struct;

void allocate_structure(structure **);

in the .c file

int main(int argc, char **argv)
{
/* Allocate all structures */
control_struct *ctrl;
allocate_structure(&ctrl);
etc...

void allocate_structure(structure **s)
{
if ((*s = malloc(sizeof(*s))) == NULL) {

Note: type here. Corrected in my version below.
fprintf(stderr, "some msg\n");
exit(EXIT_FAILURE);
}

}

it says it doesn't know what 'structure' is when it compiles.

On the surface it looks like you simply did not update Ian's example to use
your types. He wrote "void allocate_structure(structure **s)" but that
was a generic example. You'd have to use your own type:

void allocate_structure(constrol_struct **s)
{
if ((*s = malloc(sizeof **s)) == NULL) {
fprintf(stderr, "some msg\n");
exit(EXIT_FAILURE);
}
}

Note the correction to sizeof **s rather than sizeof *s.
be misunderstanding as this is what I didn't get, i.e. how to pass the
structure, what you call it when you pass it to the function.

Out of interest, why do you want to it this way? I usually prefer the
functional "return the pointer" style if it is available,
 
I

ImpalerCore

Hi,

I currently allocate a series of structures...

in the .h file

typedef struct {
    FILE *in_fp;
    etc....

} control_struct;

then in the main func:

control_struct *ctrl;
if ((ctrl = malloc(sizeof(control_struct))) == NULL) {
    fprintf(stderr, "control structure: Not allocated enough memory
\n");
    exit(EXIT_FAILURE);

}

I would like to write my own generic function to take the malloc
section to tidy up the code (as I have a number of structures to
allocate), i.e. so instead in the main I would have something like

allocate_structure(&ctrl);

and

void allocate_structure(structure *s) {
    if ((s = malloc(sizeof(structure))) == NULL) {
        fprintf(stderr, "Structure: Not allocated enough memory\n");
        exit(EXIT_FAILURE);
    }

}

But I am not sure how to pass the structure when it is unallocated,
i.e. how to set up the function declarations.

Any assistance would be very helpful

I prefer to use the same style as malloc to get an allocated block of
memory. In the same way, I also prefer to keep error handling out of
the allocation function, relying on checking NULL to determine if
there was an error.

\code
control_struct* cs_alloc( void )
{
control_struct* cs = NULL;

cs = malloc( sizeof (control_struct) );
if ( cs ) {
/* Any necessary initialization in here. */
}

return cs;
}
\endcode

You can change the style of allocation by writing a macro that takes a
type parameter instead of a size parameter.

\code
/*!
* \brief Allocate an array of objects by their type.
* \param type The object type.
* \param n The number of objects to allocate.
* \return A pointer to the allocated memory, or \c NULL if the
* requested allocation failed.
*/
#define c_new( type, n ) (malloc( sizeof (type) * (size_t)(n) ))
\endcode

This is just an allocation style that accents the 'type' rather than
the type neutral 's = malloc(sizeof *s)'. Preferences vary.

As you write more code, you'll find that you develop a particular
style of structured error handling. You can often create a macro that
wraps your style and use that macro everywhere. The bonus is that if
you ever change your style, you often only have to do it in one place,
not everywhere.

\code
/* __func__ is standard C in C99 and higher */
#if !defined(__STDC_VERSION__) /* __STDC_VERSION__ defined in C99 */
# if (defined(__GNUC__) && __GNUC__ >= 2) || defined(_WIN32) ||
defined(__WIN32__)
# define __func__ ((const char*) __FUNCTION__)
# else
# define __func__ ((const char*) "")
# endif
#endif

void my_default_report_handler( const char* msg,
const char* file,
int line,
const char* func )
{
/* In my case, if I don't have support for __func__, I define
it above to a string of "". */
if ( *func != '\0' )
{
(void)fprintf( stderr, "%s, file %s, line %d, function %s\n",
msg, file, line, func );
}
else
{
(void)fprintf( stderr, "%s, file %s, line %d\n",
msg, file, line );
}
}

#define c_return_value_if_fail( expr, msg, val ) \
do \
{ \
if ( expr ) {} \
else \
{ \
my_default_report_handler( msg, __FILE__, \
__LINE__, __func__ ); \
return (val); \
} \
} while (0)
\endcode

With that machinery in place, you can do the following if you wish.

\code
int main( void )
{
control_struct* cs;

cs = c_new( control_struct, 1 );
c_return_value_if_fail( cs != NULL,
"Structure: Not allocated enough memory",
EXIT_FAILURE );
free( cs );

return 0;
}
\endcode

The 'my_default_report_handler' function can be customized however you
wish. You can add a parameter for '#expr', log messages to a file
instead of stderr, inject a timestamp, make it a no-op if 'msg ==
NULL', popup an error dialog in Windows, ... whatever you want.

You can have also have a c_return_if_fail( expr, msg ) that just
returns instead of returning a value for functions that have 'void' as
the return type. The 'c_return_value_if_fail' macro was inspired from
GLib. Just some ideas to percolate on.

Best regards,
John D.
 

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,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top