Home > Net >  Segfault when I loop through the array of a dynamically allocated structure
Segfault when I loop through the array of a dynamically allocated structure

Time:09-23

Here's the problem, I'm trying to allocate a struct containing an array of pixels but it gives me a segfault and I can't find the error, here's how I originally tried to do it:

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

typedef struct {
    int len;
    uint16_t tex_w;
    uint16_t tex_h;
    uint32_t** tex;
} Tex_Array;

int main(void)
{
    const uint8_t tex_num = 8;
    const uint16_t tex_w = 64;
    const uint16_t tex_h = 64;

    Tex_Array* wall_tex = malloc(sizeof(Tex_Array)   (tex_w * tex_h) * tex_num * sizeof(uint32_t));

    /* Texture generation */

    for(int x = 0; x < tex_w; x  ) {
        for(int y = 0; y < tex_h; y  )
        {
            int xorcolor = (x * 256 / tex_w) ^ (y * 256 / tex_h);
            int ycolor = y * 256 / tex_h;
            int xycolor = y * 128 / tex_h   x * 128 / tex_w;
            wall_tex->tex[0][tex_w * y   x] = 65536 * 254 * (x != y && x != tex_w - y);
            wall_tex->tex[1][tex_w * y   x] = xycolor   256 * xycolor   65536 * xycolor;
            wall_tex->tex[2][tex_w * y   x] = 256 * xycolor   65536 * xycolor;
            wall_tex->tex[3][tex_w * y   x] = xorcolor   256 * xorcolor   65536 * xorcolor;
            wall_tex->tex[4][tex_w * y   x] = 256 * xorcolor;
            wall_tex->tex[5][tex_w * y   x] = 65536 * 192 * (x % 16 && y % 16);
            wall_tex->tex[6][tex_w * y   x] = 65536 * ycolor;
            wall_tex->tex[7][tex_w * y   x] = 128   256 * 128   65536 * 128;
        }
    }

    /* Test if the program arrives here */

    printf("Generation is finished !\n");

    /* rest of initialization just for example */

    wall_tex->len = tex_num;
    wall_tex->tex_w = tex_w;
    wall_tex->tex_h = tex_h;

    return 0;

}

What I understand even less is that I tried to do it even more "literally" as below, with memcpy(), but it gives me exactly the same result (segfault) at copy time :

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

typedef struct {
    int len;
    uint16_t tex_w;
    uint16_t tex_h;
    uint32_t** tex;
} Tex_Array;

int main(void)
{
    const uint8_t tex_num = 8;
    const uint16_t tex_w = 64;
    const uint16_t tex_h = 64;

    uint32_t tex[8][tex_w * tex_h];

    /* Texture generation */

    for(int x = 0; x < tex_w; x  ) {
        for(int y = 0; y < tex_h; y  )
        {
            int xorcolor = (x * 256 / tex_w) ^ (y * 256 / tex_h);
            int ycolor = y * 256 / tex_h;
            int xycolor = y * 128 / tex_h   x * 128 / tex_w;
            tex[0][tex_w * y   x] = 65536 * 254 * (x != y && x != tex_w - y);
            tex[1][tex_w * y   x] = xycolor   256 * xycolor   65536 * xycolor;
            tex[2][tex_w * y   x] = 256 * xycolor   65536 * xycolor;
            tex[3][tex_w * y   x] = xorcolor   256 * xorcolor   65536 * xorcolor;
            tex[4][tex_w * y   x] = 256 * xorcolor;
            tex[5][tex_w * y   x] = 65536 * 192 * (x % 16 && y % 16);
            tex[6][tex_w * y   x] = 65536 * ycolor;
            tex[7][tex_w * y   x] = 128   256 * 128   65536 * 128;
        }
    }

    printf("Generation is finished !\n"); // It's okay'

    /* rest of initialization */

    Tex_Array* wall_tex = malloc(sizeof(Tex_Array)   sizeof(tex));

    wall_tex->len = tex_num;
    wall_tex->tex_w = tex_w;
    wall_tex->tex_h = tex_h;

    memcpy(wall_tex->tex, tex, sizeof(tex)); // Segfault here

    /* Test if the program arrives here */

    printf("Struct alloc is finished !\n");

    return 0;

}

Where am I going wrong with using malloc()?

I want to clarify that these are just shortened examples and I need to be able to allocate this structure in the real project.

CodePudding user response:

You allocate too much space for your Tex_Array structure, you end with a double-pointer, not an actual array embedded in the struct itself.

Really, what you should have is something like:

Tex_Array *wall_tex = malloc(sizeof(Tex_Array));
wall_tex->tex = malloc(tex_num * sizeof(uint32_t *));
for (size_t i = 0; i < tex_num;   i)
    wall_tex->tex[i] = malloc((tex_w * tex_h) * sizeof(uint32_t));

assuming that is what you want to do here.

This allocates a lot, however. We can still do it one large allocation and partition it up accordingly afterwards.

Tex_Array *wall_tex;
// Note that we use (char *) here since sizeof(char) == 1.
char *arena = malloc(sizeof(Tex_Array)   (tex_w * tex_h) * tex_num * sizeof(uint32_t));

wall_tex = arena;
arena  = sizeof(Tex_Array);
wall_tex->tex = arena;
arena  = tex_num * sizeof(uint32_t *);
for (size_t i = 0; i < tex_num;   i) {
    wall_tex->tex[i] = arena;
    arena  = (tex_w * tex_h) * sizeof(uint32_t);
}

Hopefully understanding this can point you in the right direction.

CodePudding user response:

Like I said in my comment, your allocation is only for the wall_tex pointer. Which you don't really need to be a pointer or do to dynamic allocation:

Tex_Array wall_tex;  // Create one single Tex_Array structure object

Then you need to allocate the actual array for tex itself:

wall_tex.tex = malloc(sizeof *wall_tex.tex * tex_num);

And lastly create the sub-arrays:

for (unsigned i = 0; i < tex_num;   i)
{
    wall_tex.tex[i] = malloc(sizeof *wall_tex.tex[0] * tex_w * tex_h);
}

If you need to dynamically allocate the Tex_Array structure object itself, then allocate only it:

Tex_Array *wall_tex = malloc(sizeof *wall_tex);
  •  Tags:  
  • c
  • Related