0
votes

I have a structure , which present my element of data

struct myElement
{
    int field1;
    int field2;
    int field3;    
};

another structure, which contain array of this elements and some another data

struct myArray 
{
    struct myElement *elements;
    int someData;
};

and I need to have array of this arrays like that

struct myArray *myMatrix;

But I have a problem with memory allocation. Count of elements in myArray's can be different, in myMatrix too, so I need to allocate memory dynamicaly. What is the corret way to allocate and deallocate memory in this situation?

6

6 Answers

5
votes

Here's a small example of how you would allocate (malloc) and deallocate (free) a dynamic struct myElement array in a struct myArray. Note also that you will need to keep track of the size of the array, so I added size_t elements_len; to struct myArray (excuse the combination of camelCase and underscores - I use underscores in C, but didn't want to modify your identifiers):

#include <stdlib.h>

struct myElement
{
    int field1;
    int field2;
    int field3;    
};

struct myArray 
{
    struct myElement *elements;
    size_t elements_len;
    int someData;
};

void allocate_elements(struct myArray *m, size_t length)
{
   m->elements = malloc(length * sizeof( *m->elements) );
   m->elements_len = length;
}

void free_elements(struct myArray *m)
{
   free(m->elements);
   m->elements = NULL;  /* point to NULL to signify no array allocated */
   m->elements_len = 0; /* length of 0 also signifies no elements/no array */
}

int main(void)
{
   struct myArray ma;

   allocate_elements(&ma, 5);
   free_elements(&ma);

   return 0;
}

Apply similar logic in order to have a dynamic array of struct myArray. You would malloc enough memory for X amount of struct myArrays, then for each struct myArray element in that array, you would call allocate_elements. Then iterate through each element in the array once you're done with it and call free_elements.

0
votes

Use malloc to allocate the memory:

myMatrix = malloc(sizeof(myArray)*dim1);
for (int i = 0; i < dim1; i++)
    myMatrix[i].elements = malloc(sizeof(myElement)*dim2);

Use free in similar fashion to release the memory once you're done with it.

0
votes
struct myArray *myMatrix = malloc(Nentries * sizeof(*myMatrix));
if (myMatrix != 0)
{
    for (int i = 0; i < Nentries; i++)
    {
        myMatrix[i].elements = malloc(Nelements[i] * sizeof(myElement));
        if (myMatrix[i].elements != 0)
        {
            for (int j = 0; j < Nelements[i]; j++)
            {
                myElement *e = &myMatrix[i].elements[j];
                e->field1 = 0;
                e->field2 = 1;
                e->field3 = 2;
            }
            myMatrix[i].someData = 37;
        }
    }
}

I'm assuming that Nentries says how many elements there are in the matrix, and that each element of the array Nelements indicates how many elements are in the corresponding element of the matrix. The code tests for successful memory allocation, but does not react to allocation failure.

0
votes
int  num_elements = 1234;  // whatever

struct myArray *myMatrix;

myMatrix = malloc (num_elements * sizeof (*myMatrix));
if (!myMatrix)
     // error

// subsequent use of myMatrix is just like it had been statically dimensioned:
myMatrix [0].someData =  343;

myMatrix [1].someData =  323;
0
votes

You need to use malloc and free functions to dynamically allocate and free the memory. Please use the following as a reference.

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

int main()
{

    struct myElement {
        int field1;
        int field2;
        int field3;
    };

    struct myArray {
        struct myElement *elements;
        int someData;
    };

    struct myArray *myMatrix = NULL;

    int n_myarray = 0;
    int n_elements = 0;
    int i, j;

    printf("How many myArray's do you want? ");
    scanf("%d", &n_myarray);

    printf("How many elements do you want in each array? ");
    scanf("%d", &n_elements);

    /* memory allocation starts here */
    if ((myMatrix = (struct myArray *) malloc((int)sizeof(struct myArray) * n_myarray)) == NULL) {
        printf("ERROR: unable to allocate array\n");
        return 1;
    }

    for (i=0 ; i<n_myarray ; i++) {
        if ((myMatrix[i].elements = (struct myElement *) malloc((int)sizeof(struct myElement) * n_elements)) == NULL) {
            printf("ERROR: unable to allocate array elements\n");
            free(myMatrix);
            return 1;
        }

        /* initialization of other members of struct myArray goes here */
        myMatrix[i].someData = 123;

        /* initialization of members of struct myElement goes here */
        for (j=0 ; j<n_elements ; j++) {
            myMatrix[i].elements[j].field1 = 123;
            myMatrix[i].elements[j].field2 = 123;
            myMatrix[i].elements[j].field3 = 123;
        }
    }

    /* do your calculations here */
    /* I'm printing the values */

    for (i=0 ; i<n_myarray ; i++) {
        printf("myMatrix[%d].someData : %d \n", i, myMatrix[i].someData);
        for (j=0 ; j<n_elements ; j++) {
            printf("myMatrix[%d].elements[%d].field1 : %d \n", i, j, myMatrix[i].elements[j].field1);
            printf("myMatrix[%d].elements[%d].field2 : %d \n", i, j, myMatrix[i].elements[j].field2);
            printf("myMatrix[%d].elements[%d].field3 : %d \n", i, j, myMatrix[i].elements[j].field3);
        }
    }

    /* memory deallocation (free) starts here */

    for (i=0 ; i<n_myarray ; i++) {
        free(myMatrix[i].elements);
    }
    free(myMatrix);

    return 0;
}

> ./a.out
How many myArray's do you want? 2
How many elements do you want in each array? 5
myMatrix[0].someData : 123
myMatrix[0].elements[0].field1 : 123
myMatrix[0].elements[0].field2 : 123
myMatrix[0].elements[0].field3 : 123
myMatrix[0].elements[1].field1 : 123
myMatrix[0].elements[1].field2 : 123
myMatrix[0].elements[1].field3 : 123
myMatrix[0].elements[2].field1 : 123
myMatrix[0].elements[2].field2 : 123
myMatrix[0].elements[2].field3 : 123
myMatrix[0].elements[3].field1 : 123
myMatrix[0].elements[3].field2 : 123
myMatrix[0].elements[3].field3 : 123
myMatrix[0].elements[4].field1 : 123
myMatrix[0].elements[4].field2 : 123
myMatrix[0].elements[4].field3 : 123
myMatrix[1].someData : 123
myMatrix[1].elements[0].field1 : 123
myMatrix[1].elements[0].field2 : 123
myMatrix[1].elements[0].field3 : 123
myMatrix[1].elements[1].field1 : 123
myMatrix[1].elements[1].field2 : 123
myMatrix[1].elements[1].field3 : 123
myMatrix[1].elements[2].field1 : 123
myMatrix[1].elements[2].field2 : 123
myMatrix[1].elements[2].field3 : 123
myMatrix[1].elements[3].field1 : 123
myMatrix[1].elements[3].field2 : 123
myMatrix[1].elements[3].field3 : 123
myMatrix[1].elements[4].field1 : 123
myMatrix[1].elements[4].field2 : 123
myMatrix[1].elements[4].field3 : 123
>

Please ensure the following:

  • for every malloc there should be a free
  • before using the memory that was allocated using malloc you must check whether malloc successfully allocated the memory block you've requested.
0
votes

Something like this should work though it is not a great solution with so many seperate allocations, further down is a better solution. I have tried to make variable names descriptive of what they hold.

int arrayOfSubArrayLengths={9,5,10,50,...};
int lengthOfMyMatrix=something;

myMatrix= (myArray*) malloc( sizeof(myArray) * lengthOfMyMatrix);

for(int i=0; i<lengthOfMyMatrix; ++i)
{
    myMatrix[i].elements=new myElement[arrayOfSubArrayLengths];
    myMatrix[i].someData=whatever;
}

to delete:

for(int i=0; i<lengthOfMyMatrix; ++i)
{
    free( myMatrix[i].elements );
}
free( myMatrix );

However as I said that is not a great solution with so many allocations. It could cause some severe memory fragmentation depending on how large lengthOfMyMatrix is. Also so many calls to the allocator could slow things down depending once again on the size of lengthOfMyMatrix. Here is a better solution:

int arrayOfSubArrayLengths={9,5,10,50,...};
int lengthOfMyMatrix=something;
int sumOfSubArrayLengths=someNumber;

myArray* fullArray=(myElement*) malloc( sizeof(myElement) * sumOfSubArrayLengths);

myMatrix= (myArray*) malloc( sizeof(myArray) * lengthOfMyMatrix);

int runningSum=0;

for(int i=0; i<lengthOfMyMatrix; ++i)
{
    myMatrix[i].elements = &fullArray[runningSum];
    runningSum += arrayOfSubArrayLengths[i];
    myMatrix[i].someData = whatever;
}

to delete:

free( fullArray );
free( myMatrix );

In this fashion there are only two calls to the allocator no matter the various lengths. So there is far more memory fragmentation and less allocation overhead time. The one downside to the second method is that if you are not careful with bounds checking it is very easy to corrupt data in the array without knowing since the memory 'belongs' to you and thus the OS will not kick you for an access violation.