1

I'm working on an assignment for class and having some issues with assigning values to an unsigned int ** variable that is in an object. For some reason, I can not assign it with malloc stating that there is an error with assignment to expression with array type. I'm not sure what this means, I have tried to use directly malloc it to image->pixmap, but have the same issue. This happens in both methods.

P.S. As this is an assignment I can NOT change the structs/object definitions, otherwise I would have.

I will do my best to explain the pixmap for PPMImage as an example:

pixmap: Three height x width, 2-dimensional pixel arrays, for ’R’, ‘G’, ‘B’ values
height: image height (number of rows)
width: image width (number of columns)
pixmax: maximum pixel value of image

//p->pixmap[0]: ‘R’ pixmap array
//p->pixmap[1][7]: 8th row of pixels of ‘G’ pixmap array
//p->pixmap[2][4][10]: 11th pixel in 5th row of ‘B’ pixmap array
typedef struct {
unsigned int ** pixmap[3];
unsigned int height, width, pixmax;
} PPMImage;

PPMImage * new_ppmimage( unsigned int w, unsigned int h, unsigned int m )
{

    PPMImage *image;
    image = (PPMImage *) malloc(sizeof(PPMImage));
    image -> height = h;
    image -> width = w;

    unsigned int ** tempArray = malloc(sizeof(unsigned int *)*h);
    for(int i  = 0;i < h; i++){
        tempArray[i] = malloc(sizeof(unsigned int) *w);
    }
    // issue here
    image -> pixmap = tempArray;
    return NULL;
}
=======================================
typedef struct {
unsigned int ** pixmap;
unsigned int height, width;
} PBMImage;

PBMImage * new_pbmimage( unsigned int w, unsigned int h )
{
    PBMImage *image;
    image = (PBMImage *) malloc(sizeof(PBMImage));
    image -> height = h;
    image -> width = w;
    
    // issue here
    image -> pixmap = malloc(sizeof(unsigned int *)*h);
    for(int i  = 0;i < h; i++){
        image -> pixmap[i] = malloc(sizeof(unsigned int) *w);
    }
    return NULL;
}
11
  • The variable (structure member) is not just an unsigned int **; it is unsigned int **name[3]; — which is pretty horrid as a type. Are you sure you need the array part? My brain hurts just looking at it. Commented Jan 29, 2022 at 18:53
  • @JonathanLeffler well the issues persist for the other object that has an unsigned int** the PBMImage. and I am a little lost with the question of do I need the array part Commented Jan 29, 2022 at 18:55
  • Style guide: the dot . and arrow -> operators bind very tightly because they are postfix operators. They should not be written with spaces around them. Writing image -> height is not idiomatic C and indicates that the coder is a tyro (newbie). Use image->height. Commented Jan 29, 2022 at 18:57
  • So, is the array of 3 elements for RGB colour values? And in the second case you're effectively using a grey-scale? Commented Jan 29, 2022 at 18:57
  • 1
    Right now you're declaring a member variable that is an array of three pointer-to-pointer-to-unsigned int. If you can't change that, then kindly explain what that is supposed to hold, because as-written it does not make sense. It sounds like you want a pointer to pointer to array-of-three unsigned int, not an array-of-three pointer to pointer to unsigned int. Commented Jan 29, 2022 at 19:00

2 Answers 2

2

This

unsigned int ** pixmap[3];

means that pixmap is an array of size 3 containing values of the type "pointer to pointer to unsigned int". It is not possible to directly assign anything to an array type like this.

You probably want to do something like this:

image->pixmap[0] = tempArray;

This assigns tempArray to the first element of pixmap. Notice how the types of these match.

Repeat the allocation process to allocate memory for pixmap[1] and pixmap[2] as well.

Sign up to request clarification or add additional context in comments.

Comments

1

Your code will never work as you always return NULL not the allocated memory in the new_ppmimage function.

If you cant change the types:

typedef struct {
unsigned int ** pixmap[3];
unsigned int height, width, pixmax;
} PPMImage;

PPMImage * new_ppmimage( unsigned int w, unsigned int h, unsigned int m )
{

    PPMImage *image;
    image = malloc(sizeof(*image));
    if(image)
    {
        image -> height = h;
        image -> width = w;
        for(size_t i = 0; i < sizeof(image -> pixmap) / sizeof(image -> pixmap[0]); i++)
        {
            image -> pixmap[i] = malloc(h * sizeof(*image -> pixmap));
            if(image -> pixmap)
            {
                for(unsigned hi = 0; hi < h; hi++)
                {
                    image -> pixmap[i][hi] = malloc(w * sizeof(**image -> pixmap[i]));
                    if(!image -> pixmap[hi])
                    {
                        /* handle memory allocation error */
                    }
                }
            }
        }
    }
    return image;
}

and the second one. See that there is almost no difference.

typedef struct {
unsigned int ** pixmap;
unsigned int height, width;
} PBMImage;

PBMImage * new_pbmimage( unsigned int w, unsigned int h)
{

    PBMImage *image;
    image = malloc(sizeof(*image));
    if(image)
    {
        image -> height = h;
        image -> width = w;
        image -> pixmap = malloc(h * sizeof(*image -> pixmap));
        if(image -> pixmap)
        {
            for(unsigned hi = 0; hi < h; hi++)
            {
                image -> pixmap[hi] = malloc(w * sizeof(**image -> pixmap));
                if(!image -> pixmap[hi])
                {
                    /* handle memory allocation error */
                }
            }
        }
    }
    return image;
}

I would implement it using flexible array members and array pointers. Only one malloc and free are needed. Much more efficient as two levels of indirection are removed.

typedef struct {
    size_t height, width, pixmax;
    unsigned int pixmap[][3];
} PPMImage;

PPMImage * new_ppmimage( const size_t w, const size_t h, unsigned int m )
{

    PPMImage *image;
    image =  malloc(sizeof(*image) +  h * w * sizeof(image -> pixmap[0]));
    if(image)
    {
        image -> height = h;
        image -> width = w;
    }
    return image;
}

And simple usage:

unsigned int getPixelVal(PPMImage *image, const size_t x, const size_t y, const size_t index)
{
    unsigned int (*pixel)[image -> width][3] = image -> pixmap;

    return pixel[y][x][index];
}

5 Comments

I tired this and it still has the same issue at the inital malloc., pbm_aux.c:14:25: error: assignment to expression with array type 14 | image -> pixmap = malloc(h * sizeof(*image -> pixmap));
I understand whats happening in the code Im lost why it wont compile
@Bhagyesh it does compile godbolt.org/z/8845hqb93
I fixed it, issue with makefile, when i run unsigned int (*pixel)[image -> width][3] = image -> pixmap; it states that warning: initialization of ‘unsigned int (*)[(sizetype)(image->width)][3]’ from incompatible pointer type ‘unsigned int ***’
@Bhagyesh you need to use struct from other other example. Not your one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.