C create array of struct using constructor function -


i have c struct:

typedef struct {   dataset *datasets;   int ndatasets;   char *group_name;         enum grouptype type;   } datasetgroup;  

it has constructor function this:

datasetgroup * new_datasetgroup(char *group_name, enum grouptype type, enum returncode *ret) {     datasetgroup *dg;     dg = (datasetgroup *) malloc(sizeof(datasetgroup));     if (dg == null)     {      *ret = ememory_error;     }      // allocate space few datasets     dg->datasets = malloc(sizeof(dataset) * increment);     if (dg->datasets == null)     {         *ret = ememory_error;     }     dg->group_name= malloc(sizeof(char) * strlen(group_name));     strcpy(dg->group_name, group_name);     dg->type = type;     groupcount++;     return dg;   } 

i want dynamically create array of these structs. whats best way this?

so far have like:

   datasetgroup * make_array(){       datasetgroup *dg_array;      // allocate space few groups      dg_array = (datasetgroup *) malloc(sizeof(datasetgroup) * increment);       return dg_array;     }     void add_group_to_array(datasetgroup *dg_array, ...){       // add datasetgroup       datasetgroup *dg = new_datasetgroup(...);        // groupcount - 1 count incremented when group created, 1 ahead of array index want assign       dg_array[groupcount - 1] = dg;       if (groupcount % increment == 0)      {       //grow array       dg_array = realloc(dg_array, sizeof(datasetgroup) * (groupcount + increment));      }  } 

but doesnt seem right.... ideas?

a few suggestions:

  1. you have groupcount being incremented constructor function of struct. means can have 1 array of struct uses array function. recommend having array responsible managing count.
  2. to affect if want have managed array create struct , have keep both pointer array,the number of objects , size of array (e.g. maximum number of structs can hold)
  3. if keep proper track of how many elements have , size of array can replace groupcount % increment == 0 groupcount == arraysize lot more intuitive in opinion.
  4. you can avoid second malloc in constructor having array array of elements instead of array of pointers. constructor initialize struct members instead of allocating memory. if doing lot avoiding lot of memory fragmentation.
  5. finally, while depends on application, recommend when realloc not increase constant instead of multiple of current array size. if double array size have log_2 n number of reallocs n being final array size , waste @ half of memory (memory cheap, said depends on application). if wasting memory can 1.5. if want more detailed explanation of recommend this joel on software article, part realloc 2/3 down.

update:

a few others things:

dg = (datasetgroup *) malloc(sizeof(datasetgroup)); if (dg == null) {  ret = ememory_error; }  // allocate space few datasets dg->datasets = malloc(sizeof(dataset) * increment); 

as pointed out bad dg if null. want exit right after detecting error.

furthermore setting ret ret passed value not changed caller if callee changes it. instead want pass pointer , dereference it.

update 2: can give example, sure, quick not ;-d.

consider following code (i apologize if there mistakes, still half asleep):

#include <stdio.h> #include <stdlib.h>  #define less_mallocs  #define max_count 100000000  typedef struct _foo_t {   int bar1;   int bar2; } foo_t;  void foo_init(foo_t *foo, int bar1, int bar2) {   foo->bar1 = bar1;   foo->bar2 = bar2; }  foo_t* new_foo(int bar1, int bar2) {   foo_t *foo = malloc(sizeof(foo_t));   if(foo == null) {     return null;   }   foo->bar1 = bar1;   foo->bar2 = bar2;   return foo; }  typedef struct _foo_array_t { #ifdef less_mallocs   foo_t *array; #else   foo_t **array; #endif   int count;   int length; } foo_array_t;  void foo_array_init(foo_array_t* foo_array, int size) {   foo_array->count = 0; #ifdef less_mallocs   foo_array->array = malloc(sizeof(foo_t) * size); #else   foo_array->array = malloc(sizeof(foo_t*) * size); #endif   foo_array->length = size; }  int foo_array_add(foo_array_t* foo_array, int bar1, int bar2) {   if(foo_array->count == foo_array->length) { #ifdef less_mallocs     size_t new_size = sizeof(foo_t) * foo_array->length * 2; #else     size_t new_size = sizeof(foo_t*) * foo_array->length * 2; #endif     void* tmp = realloc(foo_array->array, new_size);      if(tmp == null) {       return -1;     }     foo_array->array = tmp;     foo_array->length *= 2;   } #ifdef less_mallocs   foo_init(&(foo_array->array[foo_array->count++]), bar1, bar2); #else   foo_array->array[foo_array->count] = new_foo(bar1, bar2);   if(foo_array->array[foo_array->count] == null) {     return -1;   }   foo_array->count++; #endif   return foo_array->count; }   int main() {   int i;   foo_array_t foo_array;   foo_array_init(&foo_array, 20);   for(i = 0; < max_count; i++) {     if(foo_array_add(&foo_array, i, i+1) != (i+1)) {       fprintf(stderr, "failed add element %d\n", i);       return exit_failure;     }   }    printf("added elements\n");   return exit_success; } 

there struct (foo_t) 2 members (bar1 , bar2) , struct array wrapper (foo_array_t). foo_array_t keeps track of current size of array , number of elements in array. has add element function (foo_array_add). note there foo_init , new_foo, foo_init takes pointer foo_t , new_foo not , instead returns pointer. foo_init assumes memory has been allocated in way, heap, stack or whatever doesn't matter, while new_foo allocate memory heap. there preprocess macro called less_mallocs. changes definition of array member of foo_array_t, size of initial array allocation, size during reallocation , whether foo_init or new_foo used. array , size have change reflect whether pointer or element in array. less_macro defined code following suggestion number 4, when not, more similar code. finally, main contains simple micro-benchmark. results following:

[missimer@asus-laptop tmp]$ gcc temp.c # compile less_macros defined [missimer@asus-laptop tmp]$ time ./a.out  added elements  real    0m1.747s user    0m1.384s sys     0m0.357s [missimer@asus-laptop tmp]$ gcc temp.c #compile less_macros not defined  [missimer@asus-laptop tmp]$ time ./a.out  added elements  real    0m9.360s user    0m4.804s sys     0m1.968s 

not time best way measure benchmark in case think results speak themselves. also, when allocate array of elements instead of array of pointers , allocate elements separately reduce number of places have check errors. of course has trade-offs, if example struct large , wanted move elements around in array doing lot of memcpy-ing opposed moving pointer around in approach.

also, recommend against this:

dg_array = realloc(dg_array, sizeof(datasetgroup) * (groupcount + increment)); 

as lose value of original pointer if realloc fails , returns null. previous ret, should pass pointer instead of value not changing value caller, callee exits has no real affect. finally, noticed changed function definition have pointer ret need dereference pointer when use it, should getting compiler warnings (perhaps errors) when try have.


Comments

Popular posts from this blog

facebook - android ACTION_SEND to share with specific application only -

python - Creating a new virtualenv gives a permissions error -

javascript - cocos2d-js draw circle not instantly -