0

I'm brushing up on some C programming, and trying to understand why I cannot print a data item from a structure (struct) after dynamically allocating memory to for structure.

I tried printing the data items in the struct to see what values I get but my code does not compile, and I get an error.

 #include <stdio.h>
 #include <stdlib.h>

 typedef struct Collection {

     int age;
     char date[20];
     char name[20];
 } Collection;

 int main(void) {

     int i;
     int n = 10;

     Collection **dataCollection;
     dataCollection = malloc(sizeof(Collection*)*n);
     dataCollection->age = 20;

for(i = 0; i < n; i++) {

    dataCollection[i] = malloc(sizeof(Collection)*n);
    printf("Data collection item: %d\n", dataCollection->age);
}

for(i = 0; i < n; i++)
    free(dataCollection[i]);
   free(dataCollection);
   return 0;
 }

I get the following errors:

practice1019.c:18:20: error: member reference base type 'Collection *' (aka 'struct Collection *')
      is not a structure or union
     dataCollection->age = 20;
     ~~~~~~~~~~~~~~^ ~~~

practice1019.c:23:56: error: member reference base type 'Collection *' (aka 'struct Collection *')
      is not a structure or union
    printf("Data collection item: %d\n", dataCollection->age);
  • 1
    `dataCollection` is a `Collection**`, but you are treating it like a `Collection*`. Start by naming your types and variables appropriate; "Collection" is not the best name for a record of a collection (as opposed to the collection itself) – ikegami Oct 20 '19 at 09:35
  • 1
    `dataCollection->age = 20;` attempts to dereference `dataCollection` (which at that point is nothing but a pointer to a block of memory holding 10 uninitialized *pointers*. Won't work. – David C. Rankin Oct 20 '19 at 09:46
  • And you have multiple `free(dataCollection)` in your last `for` loop. You should take it out. The lines are there, but just not in the right position :) – Matthieu Oct 20 '19 at 09:56

1 Answers1

1

Continuing from the comment, you cannot assign dataCollection->age = 20; after merely allocating a block of memory sufficient to hole 10 pointers-to Collection. You have allocated memory for the pointers, but not storage for the stucts themselves.

Additionally, you must validate every allocation, e.g.

    dataCollection = malloc(sizeof(Collection*)*n);

    if (!dataCollection) {  /* validate EVERY allocation */
        perror ("malloc-dataCollection");
        return 1;
    }

Now, before you can assign a value to a member of any struct, you must allocate a block of memory to hold the struct and then assign the starting address for that block to one of the pointers you have just allocated, e.g.

    for (i = 0; i < n; i++) {
        dataCollection[i] = malloc(sizeof(Collection));
        if (!dataCollection[i]) {   /* ditto */
            perror ("malloc-dataCollection[i]");
            return 1;
        }

(note: above there is no * n after Collection in sizeof(Collection) -- or you will over-allocate by a factor of 10 on struct storage...)

Now, you have storage for a struct and you can make use of the members (age below)

        dataCollection[i]->age = i + 20;
        printf("Data collection[%d] age: %d\n", i, dataCollection[i]->age);
    }

Good job on the free of each of the structs and then the pointers. Putting it altogether, you could do:

#include <stdio.h>
#include <stdlib.h>

typedef struct Collection {
    int age;
    char date;
    char name;
} Collection;

int main (void) {

    int i;
    int n = 10;

    Collection **dataCollection;
    dataCollection = malloc(sizeof(Collection*)*n);

    if (!dataCollection) {  /* validate EVERY allocation */
        perror ("malloc-dataCollection");
        return 1;
    }

    for (i = 0; i < n; i++) {
        dataCollection[i] = malloc(sizeof(Collection));
        if (!dataCollection[i]) {   /* ditto */
            perror ("malloc-dataCollection[i]");
            return 1;
        }
        dataCollection[i]->age = i + 20;
        printf("Data collection[%d] age: %d\n", i, dataCollection[i]->age);
    }

    for(i = 0; i < n; i++)
        free(dataCollection[i]);
    free(dataCollection);
}

Example Use/Output

$ ./bin/datacollection
Data collection[0] age: 20
Data collection[1] age: 21
Data collection[2] age: 22
Data collection[3] age: 23
Data collection[4] age: 24
Data collection[5] age: 25
Data collection[6] age: 26
Data collection[7] age: 27
Data collection[8] age: 28
Data collection[9] age: 29

Look things over and let me know if you have questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • I'd like to +2 for the *validate every allocation*. People coming to C from "higher level" languages tend to assume every `malloc()` will just work ... until it doesn't. – Matthieu Oct 20 '19 at 09:58
  • 1
    Yep, it's not a matter of `"if"`, but a matter of `"when"` it will fail `:)` – David C. Rankin Oct 20 '19 at 09:59