0

I have a code with a memory allocation for 3D array called "matrix" which I generally index for the x,y,z direction as matrix[i][j][k] where i,j and k are the index in x, y and z direction respectively. The allocation procedure that has been followed in the code is as follows ( lr is just a typedef for double )

lr ***lr_3D_matrix(int m, int n, int o)/**  \brief create a 3D matrix with size [m, n,o] of type lr*/
{
    lr ***matrix;
    int i, j;
    matrix =  malloc(m * sizeof(lr **));    //allocate first dimension
    matrix[0] =  malloc(m * n * sizeof(lr *));  //allocate continous memory block for all elements
    matrix[0][0] = malloc(m * n * o * sizeof(lr))
    for(j = 1; j < n; j++)  //fill first row
    {
        matrix[0][j] = matrix[0][j - 1] + o;    //pointer to matrix[0][j][0], thus first element of matrix[0][j][o]
    }

    for(i = 1; i < m; ++i)
    {
        matrix[i] = matrix[i - 1] + n;  //pointer to position of  to matrix[i][0]
        matrix[i][0] = matrix[i - 1][n - 1] + o;    //pointer to  matrix[i][j][0];
        for(j = 1; j < n; ++j)
        {
                    matrix[i][j] = matrix[i][j - 1] + o;
        }
    }
    return matrix;
}

Now, I want to port this code in a way that this matrix can be accessed in a same way using Shared Memory IPC with another code. So if i declare the memory as

ShmID = shmget(ShmKEY, m*n*o*sizeof(lr), IPC_CREAT | 0666);

then how should I attach this block of memory to a tripple pointer such that the memory access remains same ?

example for attaching this as a single pointer I can write

matrix = (lr *) shmat(ShmID, NULL, 0);

Also I am bit struggling with the for loops in the original code and what they are actually doing ?

Edit: ShmKEY is just an identifier known apriori.

datapanda
  • 437
  • 1
  • 5
  • 12
  • @Someprogrammerdude my fault, it was a typo. Indeed it should be m*n*o*sizeof(lr). But the question still remains as it is. ( it was a typo, now corrected) – datapanda Apr 06 '18 at 08:58
  • 2
    You need to use actual 3D arrays instead. See [Correctly allocating multi-dimensional arrays](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays). – Lundin Apr 06 '18 at 09:34
  • I would say that `matrix[0][0] = shmat(ShmID, NULL, 0);` and everything else stays the same. – user3386109 Apr 06 '18 at 09:35
  • @user3386109 I did get your point but then there would have to be assignment for matrix (as ***), matrix[0] (as **) and then they would have to be interweaved such that one can again access the matrix as `matrix[i][j][k]` ( This is with reference to the other code which needs access to matrix . For this code I do get your point that changing only the line will keep other things intact. ) – datapanda Apr 06 '18 at 09:40
  • The assignments for `matrix` and `matrix[0]` don't need to be in the shared memory. Only the `double` values themselves need to be in the shared memory. OTOH Lundin is correct that you can declare a pointer `lr (*matrix)[n][o] = shmat(ShmID, NULL, 0);` and use that instead, assuming the compiler supports VLAs. – user3386109 Apr 06 '18 at 09:50
  • @user3386109 aah I see the point now – datapanda Apr 06 '18 at 10:03
  • @Lundin a great Q&A you have pointed to. Thanks – datapanda Apr 06 '18 at 10:04
  • @Lundin I did look at your link ( and your well written answer ). On a side note does my code for 3D array suffer from fragmented allocation as you have pointed in the case of pointer to pointer allocations since the line `matrix[0][0] = malloc(m * n * o * sizeof(lr))` allocates a contiguous block of memory although the two pointers corresponding to `matrix[0]` and `matrix` may fall contiguously or may not. – datapanda Apr 06 '18 at 19:08
  • Yes it does since you have multiple calls to malloc. But that's a lesser problem here, as I make no sense out of your allocation code or algorithm in the first place. You seem to be allocating way too much memory and your pointer arrays are not properly initialized. – Lundin Apr 09 '18 at 06:35

1 Answers1

2

In a slight note of pedantry, an array is a single allocation, so what you have can't be a 3D array. It's much more like a tree, designed to emulate a 3-dimensional array.

For example, you have your root node:

matrix =  malloc(m * sizeof(lr **));    //allocate first dimension

Then you have some leaf nodes:

matrix[0] =  malloc(m * n * sizeof(lr *));

Then you have a block of memory that each of the leaf nodes points into:

matrix[0][0] = malloc(m * n * o * sizeof(lr)); // note: you were missing a semicolon here

You really only need the last allocation. One allocation is better than many, when you're talking about one array. Here's an example of allocating a 3-dimensional array, if you can call it that...

typedef lr lr_[o];
typedef lr_ lr__[n];
lr__ *matrix = malloc(m * sizeof matrix[0]);
free(matrix); /* you should probably error check and use your memory first,
               * but we're done with this example now, and when we're done
               * with something `malloc`'d we `free` it.
               */

*Note: As pointed out below, you can lose the typedefs and use the more complex (though not by far), condensed notation.


ShmID = shmget(ShmKEY, m*n*o*sizeof(lr), IPC_CREAT | 0666);

then how should I attach this block of memory to a tripple pointer such that the memory access remains same ?

matrix = (lr *) shmat(ShmID, NULL, 0);

This last line of code is essentially equivalent to matrix[0][0] = malloc(m * n * o * sizeof(lr)), from your question... so I think you should consider changing that line to:

matrix[0][0] = shmat(ShmID, NULL, 0);

However, if you wanted to use a single allocation like I have done, then you could write:

ShmID = shmget(ShmKEY, m * n * o * sizeof (lr));
lr__ *matrix = shmat(ShmID, NULL, 0);
shmdt(matrix); // as I understand, `shmdt` is roughly analogous to `free`

Then you won't need the loops to construct your tree. ;)

Community
  • 1
  • 1
autistic
  • 1
  • 3
  • 35
  • 80
  • 1
    Once you get it, I find that `lr (*matrix)[m][n] = malloc(...)` to be more readable then such typedefs. – KamilCuk Aug 12 '18 at 10:34
  • nice to the point. I use out of file scope declarations and definitions for the matrix tripple pointers as these large matrices are used throughout the code as global variables. In case I use your way of allocating the matrices then what should be the out of scope file declarations look like for the matrix. – datapanda Aug 12 '18 at 12:25
  • should `extern lr__ *matrix` and `lr__ *matrix` work ? – datapanda Aug 12 '18 at 12:46
  • @datapanda Sure, so long as both modules realise that they're talking about the same types... You might also want to think about some method to share dimensions. – autistic Aug 12 '18 at 15:19
  • @datapanda More to the point, `m`, `n` and `o` should probably be either hardcoded or also have some `extern`al exposure. – autistic Aug 12 '18 at 15:24
  • @autistic yeah that sounds reasonable and moreover my m n o are kind of defined like that only. Using this way of declaration I presume I can still refer to the matrix elements as `matrix[i][j][k]` – datapanda Aug 12 '18 at 15:48
  • @autistic now the function operates on the loops using `for(all i) for (all j) for (all k) matrix[i][j][k] = something` – datapanda Aug 12 '18 at 16:02
  • I am getting an error saying initializer element is not a constant (pointing to the malloc line specified by you).For eg. i am trying `typedef lr lr_[5];` `typedef lr_ lr__[5];` followed finally by the error line `lr__ *a = malloc( (5) * sizeof a[0]);` – datapanda Aug 12 '18 at 21:01
  • @KamilCuk this i guess is a VLA declaration. I can't use an out of file scope declarations(many of my large arrays are global vars) for VLA otherwise they would have been really easy to implement in the current code. – datapanda Aug 12 '18 at 21:04
  • `lr (*matrix)[m][n]` is a pointer to a a matrix m rows and n columns of `lr` variables. It's a single variable, not a vla. `int m, n; lr *matrix[m][n];` is a matrix of m rows and n columns of pointers to `lr` variables. So there are m * n pointers, many pointers, that's VLA. I mean, why don't you try it: `main() { int a[8] = {1,2,3,4,5,6,7,8}; int (*b)[2][2] = (void*)a; for (x<2) for(y<2) for(z<2) printf("[%d,%d,%d] = %d\n", x, y, z, b[x][y][z]);` – KamilCuk Aug 12 '18 at 21:57
  • @datapanda In my example I used `o` as the first index... I don't know where you're getting `i`, `j` and `k` from? Would you stop switching the indexes, please? You can see examples of what I now realise I should've shown to begin with (and I'm about to edit into this answer) [here](https://ideone.com/4aIgbq). The first four lines show what Kamil is explaining. The others what I explained. I tried all of the `malloc` lines that I wrote and they all seem to compile and execute for me... [even the lines you wrote worked](https://ideone.com/lNjmSN), though I kind of had to fill in the blanks. – autistic Aug 13 '18 at 04:38