views:

3534

answers:

4

The following is a simplified version of what I'm trying to do, because I'm sure you don't want to wade through an entire set of structs and function prototypes for a particle system.

float const materials[24][4][4] = {{{...}}};
typedef struct EmitterStruct  { float *material[4][4]; } Emitter;
typedef struct ParticleStruct { float material[4][4]; } Particle;
Emitter *myEmitter;

Emitter * createEmitter(float *material[4][4])
{
    Emitter * newEmitter;
    newEmitter = (Emitter *)malloc(sizeof(Emitter));
    newEmitter->material = materal; /* Returns "incompatable types in assignment" */
    return newEmitter;              /* I also tried newEmitter->material = &material */
}

int main(char *argv, int argc)
{
    myEmitter = createEmitter(materials[0]);
}

In essence, as the comment shows, I get a compile error. I've tried this several different ways, even using "float material[4][4]" in the Emitter struct and the signature of createEmitter. However, then later on when I try to copy values into a particle for modificaitons using:

for (i=0; i++; i<4)
{
    for (j=0; j++; j<4)
    {
        particle->material[i][j] = emitter->material[i][j];
    }
}

I get another type mismatch when copying, even though everything is declared as type float[4][4]. In essence, I want to get a 4x4 array out of an array of 4x4 arrays, keep note of it in the emitter struct, then copy it into the particle struct. But I only want to actually copy the values one time.

+1  A: 

In regard to the first snippet, you get that error because arrays in C are not assignable. You have to perform a memcpy to copy arrays.

In regard to the second snippet, you have an issue with the following line:

particle->material[i][j] = emitter->material[i][j];

The member material in Emitter is a 2d array of type float*. The member material in Particle is of type float. Note that one is a pointer and one is not, which is why they are not assignable.

You could write the following:

particle->material[i][j] = *(emitter->material[i][j]);

But that is assuming you've assigned those pointers to point at something. Alternatively, you can change material in Emitter to be a non-pointer. I can't tell you which you should do for sure because it is hard for me to decipher what your exact intentions are based on the code you've given.

fpsgamer
I figured out what I was doing wrong. And I do admit, it's rather confusing. However, cutting and pasting the full code would have been 3 files worth and even more confusing. Thank you, though.
A: 

Of course, the second I ask for help, I figure out exactly what I needed to do.

float const materials[24][4][4] = {{{...}}};
typedef struct EmitterStruct  { float *material; } Emitter; /*Use just a plain pointer*/
typedef struct ParticleStruct { float material[4][4]; } Particle;
Emitter *myEmitter;

Emitter * createEmitter(float *material) /*Use a plain pointer here*/
{
    Emitter * newEmitter;
    newEmitter = (Emitter *)malloc(sizeof(Emitter));
    newEmitter->material = material; 
    return newEmitter;               
}

int main(char *argv, int argc)
{
    myEmitter = createEmitter(materials[0]);/*This decays into a pointer*/
}

And then for the copy:

for (i=0; i++; i<4)
{
    for (j=0; j++; j<4)
    {
        particle->material[i][j] = *(emitter->material[i * 4 + j];
    }
}

Doh...

A: 

I used to be an expert on this. Unfortunately, I have been out of it for too long. So here is a working code snippet that I wrote about 6 years ago. I think that it may point you in the right direction.

// get a color histogram of an image
int ***colorHistogram(PIXEL *inputImage, HEADER *imageHeader)
{
    int x, y, z;

    // a color histogram
    int ***histo;

    // allocate space for the histogram
    histo = (int ***)malloc(256 * sizeof(int**));
    for(x=0; x<256; x++)
    {
        histo[x]=(int **)malloc(256 * sizeof(int*));
        for(y=0; y<256; y++)
        {
            histo[x][y]=(int *)malloc(256 * sizeof(int));

            // initialize the histogram
            for(z=0; z<256; z++)
                histo[x][y][z] = 0;
        }
    }

    // fill the histogram
    for (x = 0; x < imageHeader->width * imageHeader->height; x++)
    {
        histo[((int) inputImage[x].r)][((int) inputImage[x].g)][((int) inputImage[x].b)]++;
    }

return histo;

}

Anyway, I hope that helps.

PaulMorel
+3  A: 

I'm answering to your updated question (which appeared in your own answer). First your code:

float const materials[24][4][4] = {{{...}}};
typedef struct EmitterStruct  { float *material; } Emitter; /*Use just a plain pointer*/
typedef struct ParticleStruct { float material[4][4]; } Particle;
Emitter *myEmitter;

Emitter * createEmitter(float *material) /*Use a plain pointer here*/
{
    Emitter * newEmitter;
    newEmitter = (Emitter *)malloc(sizeof(Emitter));
    newEmitter->material = material; 
    return newEmitter;               
}

int main(char *argv, int argc)
{
    myEmitter = createEmitter(materials[0]);/*This decays into a pointer*/
}

NO! That's not the right way. It decays to a pointer - yes, but not a pointer to a float! If you pass materials[0], you will get a float const[4][4] which decays to float const(*)[4] (a pointer to its first element), and that pointer is what is passed. Thus, you want to change it into this:

float const materials[24][4][4] = {{{...}}};
/*Use just a plain pointer to an array */
typedef struct EmitterStruct  { float const (*material)[4]; } Emitter; 
typedef struct ParticleStruct { float material[4][4]; } Particle;
Emitter *myEmitter;

/*Use a plain pointer here. Bet keep it float const, not only float!*/
Emitter * createEmitter(float const (*material)[4])
{
    Emitter * newEmitter;
    newEmitter = (Emitter *)malloc(sizeof(Emitter));
    newEmitter->material = material; 
    return newEmitter;               
}

int main(int argc, char ** argv) /* you swapped args here */
{
    myEmitter = createEmitter(materials[0]); /* This decays into a pointer */
}

Read about it here: http://stackoverflow.com/questions/274865/pointer-question-in-c#274943. Read here about how to pass arrays properly: http://stackoverflow.com/questions/308279/c-vs#308724. I would recommend you a good C or C++ book mate :)

Johannes Schaub - litb
Granted, I haven't run the code, but are you sure that it doesn't turn into a float pointer when passed into the createEmitter function? It's bad C, sure, but I also have a hunch that it might work.
Kyle Cronin
it won't turn into float* by the life of me :) i mean what do you expect doing material[1] ? you will end up at materials[0][1] skipping sizeof(float[4]) bytes. if it were a float*, doing material[1], you would only skip sizeof(float) bytes, thus ending up somewhere between dimensions. alien time!
Johannes Schaub - litb
Yes, the size of the pointer will be off, but I don't see anywhere in the code where that's relevant. I could be wrong though as I haven't looked closely.
Kyle Cronin
well. if he doesn't care about the type he can use a void*. all other types like float* don't work. but i don't see any reason why to introduce unsafety using void*. just use the correct one :)
Johannes Schaub - litb