-1

My question is similar to this. Imagine this structure :

  typedef struct {
        char *chromosome,*sequence;
        int start,end;
    } localisation_t;

I want to allocate memory for an array (5 elements) of this structure. I will try something like : ( the syntax is certainly wrong, as you can assumed i'm not fluent in C ).

localisation_t *locs = (localisation_t*) calloc(5, sizeof(localisation_t));
strArray[0] = (localisation_t* ) malloc(sizeof(localisation_t));

I have often seen that a struct member can allocate memory too. I don't understand what for because you already allocate memory for the struct ?! But ok you don't know what it will contains. (here an example with strdup on the name variable member). Is it a good practice to allocate memory for member of struct (mostly when it's char * type) ?

What will happen if I don't do this ? Is it a good practice ?

Community
  • 1
  • 1
ZheFrench
  • 1,164
  • 3
  • 22
  • 46
  • 2
    Your question doesn't really make much sense. And what is `strArray` anyway? – juanchopanza Sep 18 '15 at 14:32
  • OB link: [don't cast the return of `malloc` (and family) in C](http://stackoverflow.com/a/605858/440558). – Some programmer dude Sep 18 '15 at 14:33
  • @Joachim Pileborg : even if you then use a c++ compiler ? I read somewhere it was necessary in C++ however. – ZheFrench Sep 18 '15 at 14:37
  • @ZheFrench : You need the cast if you compile with a C++ compiler. – Andreas Sep 18 '15 at 14:38
  • 1
    @ZheFrench: Yes, C++ requires you to cast the result of `malloc` (C++ does not allow implicit conversions between `void *` and other pointer types). However, if you're writing C++, you should be using the `new` operator instead of `malloc` (and if you can, you should use a standard container type like `vector` or `map` that handles all the memory management for you). – John Bode Sep 18 '15 at 14:38
  • `strArray` is unrelated to `locs` — so the reason there is that you need an array and a single variable. If a member of a structure needs to point at memory that isn't yet allocated, you have to allocate that, too. As a C programmer, you _must_ know (it is absolutely crucial that you know) where memory is pointed and how you should clean it up. You can't afford not to know. – Jonathan Leffler Sep 18 '15 at 14:40
  • When you allocate memory for a `localisation_t`, you're only allocating memory to store the pointers (and the other structure fields), not the contents they point to. – Filipe Gonçalves Sep 18 '15 at 14:41
  • @juanchopanza : As i said this is certainly wrong. i can remove it if you prefer , the idea was to create an array for which each index will allocated memory to store a struct. – ZheFrench Sep 18 '15 at 14:42

2 Answers2

1

When you do this:

localisation_t *locs = (localisation_t*) calloc(5, sizeof(localisation_t));

You create an 5 element array of localisation_t. You can then safely access for example locs[0].start.

You can also access locs[0].chromosome, however this is an uninitialized pointer. You need to allocate space for it:

locs[0].chromosome = strdup("my value");

Later, when you clean up, you'll need to call free the chromosome and sequence fields in each array member before calling free on the array itself:

for (i = 0; i < 5; i++) {
    free(locs[0].chromosome);
    free(locs[0].sequence);
}
free(locs);
dbush
  • 205,898
  • 23
  • 218
  • 273
1

I'm assuming you're asking whether you also need to allocate memory for chromosome and sequence to point to.

The answer is: it depends. You can set them to point to string literals or to other arrays, so in those cases you don't have to allocate any additional memory. However, if each instance of localisation_t is supposed to have it's own unique instances of chromosome and sequence, then yes, you will need to allocate memory for them as well:

char seq[] = "CGCTATCCC";
localisation_t *locs = calloc( 5, sizeof *locs ); 
...
locs[0].sequence = "CGCTATCCC";          // set sequence to point to string literal
locs[1].sequence = seq;                  // set sequence to point to another array
locs[2].sequence = strdup( "GGCCGGTT" ); // allocate memory for a duplicate string, 
                                         // set sequence to point to it

locs[3].sequence = malloc( strlen( "GGCCGGTT" ) + 1 ); // same as above, assumes
locs[3].sequence = strcpy( "GGCCGGTT" );               // strdup isn't available

...

free( locs[3].sequence );
free( locs[2].sequence );
/**
 * Don't need to free locs[1].sequence or locs[0].sequence, since they
 * point to objects that were not allocated using malloc or calloc
 */
free( locs );
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • Yes, that's the point i'm trying to resolve. I understand your code but i'm not feeling comfortable with the concept of unique instances of chromosome and sequence. Could you tell me more about that idea ? – ZheFrench Sep 18 '15 at 15:09
  • @ZheFrench - basically, I'm asking if each instance of `localisation_t` is meant to have its own unique copies of `chromosome` and `sequence`, even if they contain the same values (for example, both `locs[0]` and `locs[2]` refer to sequence "ACCGT" at "ch1", but for whatever reason you don't want them to share the memory those values are stored in). – John Bode Sep 18 '15 at 15:17