Home > Software design >  Initializing a dynamically allocated array with a compound literal
Initializing a dynamically allocated array with a compound literal

Time:01-21

I am allocating memory for my float3x3 matrix as such:

typedef float float3x3[3][3];
float3x3 *g = malloc(sizeof g);
g = &(float3x3){
    { 1, 0, 0 },
    { 0, 1, 0 },
    { 0, 0, 1 }
};
printfloat3x3(*g);

The above compiles, however I am allocating space for *g then setting g's pointer to a static 3x3 matrix. Not exactly what I want to do if I want to free g.

How can I initialize g using a compound literal after allocation? I tried this but it wont compile:

typedef float float3x3[3][3];
float3x3 *g = malloc(sizeof g);
g = (float3x3){
    { 1, 0, 0 },
    { 0, 1, 0 },
    { 0, 0, 1 }
};
printfloat3x3(*g);
free(g);
cc -fsanitize=address -Wall -Wextra -pedantic -O2 -o test-gmath test-gmath.c gmath.c -lm
test-gmath.c: In function ‘GMATH_Tests’:
test-gmath.c:69:11: warning: assignment to ‘float (*)[3][3]’ from incompatible pointer type ‘float (*)[3]’ [-Wincompa
tible-pointer-types]
   69 |         g = (float3x3){
      |           ^
test-gmath.c:75:9: warning: ‘free’ called on unallocated object ‘({anonymous})’ [-Wfree-nonheap-object]
   75 |         free(g);
      |         ^~~~~~~
test-gmath.c:69:23: note: declared here
   69 |         g = (float3x3){
      |                       ^

(3 of 11): warning: assignment to ‘float (*)[3][3]’ from incompatible pointer type ‘float (*)[3]’ [-Wincompatible-poi
nter-types]

CodePudding user response:

Typedef arrays are confusing. It's not possible to assign an array. Yoyu can't do:

float a[3][3];
float b[3][3];
a = b;

The same way you can't:

typedef float float3x3[3][3];
float3x3 *a = ...
*a = anything

Do not use typedef arrays. Use a structure.

struct float3x3 {
     float v[3][3];
};
struct float3x3 *g = malloc(sizeof(*ga));
*g = (struct float3x3){
   .v = {
       { 1, 0, 0 },
       { 0, 1, 0 },
       { 0, 0, 1 },
   }
};

CodePudding user response:

First, you need to allocate the size of the structure, not the pointer:

float3x3 *g = malloc(sizeof *g);

Then to initialize the contents, you can use memcpy()

memcpy(g, &(float3x3){
    { 1, 0, 0 },
    { 0, 1, 0 },
    { 0, 0, 1 }
}, sizeof *g);

Your code causes a memory leak because you're reassigning the pointer to point to the memory of the compound literal. That's also why free() fails, because it no longer points to the memory returned by malloc().

CodePudding user response:

In this code snippet

typedef float float3x3[3][3];
float3x3 *g = malloc(sizeof g);

The pointer g has the type float ( * )[3][3].

And sizeof( g ) is equivalent to sizeof( float ( * )[3][3] ). So you are allocating memory for a pointer not for an array of the type float3x3.

And this statement

g = &(float3x3){
    { 1, 0, 0 },
    { 0, 1, 0 },
    { 0, 0, 1 }
};

results in a memory leak because at first the pointer pointed to a dynamically allocated memory and then it was reassigned with the address of the compound literal. So the address of the allocated memory is lost.

Instead of using a pointer of the type float ( * )[3][3] you need to use a pointer of the type float ( * )[3].

#include <string.h>

//...

typedef float float3x3[3][3];

float ( * g )[3] = malloc( sizeof( float3x3 ) );
memcpy( g, (float3x3){ { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }, sizeof( float3c3 ) ); 
  • Related