-6

I've gotten rid of the codes that do work as they were distracting. What I'm trying to do is allocate a single block of memory for a 3D array. I could simply just do the allocation as a jagged array, but it's more efficient to do a contiguous block.

Here's my current code snippet:

//Creating an array of proper size
//I first create an array of pointers
phi = new double**[xlength];
//I then create another array of pointers
phi[0] = new double*[xlength*ylength];
//At this point, I assume phi[0] and phi[0][0] have the same location. Is this not true?
phi[0][0] = new double[xlength*ylength*tlength];
//Now, I allocate the big block of data that will actually store my data
//I assume phi[0][0][0] has the same location as phi[0][0]. Is this right?
//Now, I'm trying to setup the pointers to match up in the single block of memory
    for (int i=0;i<xlength;i++)
    {
        for (int j=0;j<ylength;j++)
        {
            phi[i][j] = phi[0][0] + tlength*ylength*i + tlength*j;
        }
    }
//Does this not work? It feels as though it SHOULD

Adding back working code since answer depends on working code

double*** A = new double**[m];
double**  B = new double*[m*n];
double*   C = new double[m*n*o];
for (int i=0; i<m; i++) {
    for (int j=0; j<n; j++) {
        B[n*i+j] = C + (n*i+j)*o;
    }
    A[i] = B + n*i;
}
for (int i=0; i<m; i++) {
    for (int j=0; j<n; j++) {
        for (int k=0; k<o; k++) {
            A[i][j][k] = <my_value>;
        }
    }

Here's the solution guys!

Don't do 3D matrix, LOL! This is my most unpopular post ever!

Do a 1D matrix and follow the answer on this link C++ Segmentation Fault After When Trying to Write to Matrix

This is the important part of that link:

but then you cannot use the phi[i][j][k] notation, so you should

#define inphi(I,J,K) phi[(I)*xlength*ylength+(J)*xlength+(K)]

and write inphi(i,j,k) instead of phi[i][j][k]

Community
  • 1
  • 1
Mechy
  • 259
  • 1
  • 4
  • 14
  • You need to explain what you're trying to do, especially since (1) your variable names explain nothing and (2) both of these seem to be rather unorthodox ways for allocating matrices. – Anubhav C May 15 '13 at 07:37
  • @Anubhav http://stackoverflow.com/questions/16555862/how-do-i-allocate-one-block-of-memory-with-new – Suvarna Pattayil May 15 '13 at 07:37
  • @SuvP that was a good discussion, and I'm very thankful for all the help I got. It doesn't explain why my own implementation doesn't work though. – Mechy May 15 '13 at 07:50
  • @Spook I got that code from a reliable textbook though, and I've utilized it in programs before. I'm VERY confident that it works. – Mechy May 15 '13 at 08:15
  • @Mechy if the textbook recommends using `new[]`, it's anything but reliable. – Bartek Banachewicz May 15 '13 at 08:29
  • Yeah, it actually wanted to go malloc instead, but I heard you can do everything with new you can do with malloc. – Mechy May 15 '13 at 08:31
  • Because you can, but the point is not to use new[] or malloc, but standard containers like std::vector, which does all the memory management for you (and sometimes even more efficiently than you would do) – Spook May 15 '13 at 10:19
  • @Mechy your proposed `#define` still sucks. If you are writing C++, not C, wrap it an RAII-enabled class and overload `operator()`. This macro isn't really solving the problem – Bartek Banachewicz May 15 '13 at 11:36
  • @Bartek Banachewicz How is it not solving the problem? Not only is the matrix 1D (easy to free the memory), but it's also pretty simple to use in a for loop. Does the macro slow things down or something? Is that why it's not good? – Mechy May 17 '13 at 02:49
  • @mechy Explaining this would take more space that is allowed here. I suggest you skim through the search results for "why macros are bad". In your particular case, what if I wanted two arrays? – Bartek Banachewicz May 17 '13 at 06:55

1 Answers1

2

Remarks:

  • You do not free allocated memory by using delete[]. That's a very bad practice. You always should remember to free memory you allocated.

  • It is very, very uncomfortable to choose jagged arrays (arrays of arrays) for long term use. A lot easier solution is to allocate a single array:

    double * phi = new double[xlength * ylength];
    

    And then access (x, y)-th element as following:

    phy[y * xlength + x] = 20.0;
    

    The allocation takes less time, you have a lot less things to free (only the phi itself) and access time is more-less equally fast.

  • Consider using std::vector or std::array. Since you use C++ and not C, the natural way is to use these containers instead of raw arrays, they are a lot more managable and they care themselves to free their contents if allocated statically. In your case it would look like:

    #include <vector>
    
    (...)
    
    std::vector<std::vector<double> > phi;
    
    phi.resize(xlength);
    for (int x = 0; x < xlength; x++)
        phi[x].resize(ylength);
    

Solution:

Your solution won't work. The reason, why author of the original code uses three variables is, that one of them has to contain the actual data and two others serve as pointers to parts of the original data.

In your case, you try to keep both the data and pointers to parts of the data in the same array, what simply cannot work. If you want the [][][] notation, you have to allocate jagged arrays in nested loops, just as I've shown in my solution. On the other hand, if you want one array to keep single block of data and another to keep pointers, you'll have to do it as author of the first piece of code did.


It took me a few minutes of time to figure out, how the three-dimensional solution with three variables actually work, so I'll leave an explanation for everyone, who'll encounter this thread.

The general idea is to have one variable with actual data and two proxy variables with a set of pointers, which allows addressing the actual data with [][][] notation.

C contains the actual data, so it is of size [zDim * yDim * xDim]. You can access (x, y, z) element by addressing it by [z * xDim * yDim + y * xDim + x]. [][][] notation means, that the data is organized by slices (z), which contains rows (y), which contains elements(x).

You construct array B containing pointers to all rows, ordered by slice. So B contains: (slice 0, row 0), (slice 0, row 1), ..., (slice 0, row yDim - 1), (slice 1, row 0), ...

Then, you construct array A containing pointers to elements of array B, such that z-th element of A points to (z * yDim) = 0-th row of z-th slice. Finally, when you address the array A, it works like following:

  • A[z] contains address to element of array B containing pointer to 0th row of zth slice
  • A[z][y] moves this pointer, such that now we have actual pointer to 0-th element of y-th row of z-th slice.
  • Finally, A[z][y][x] shifts us by x elements, such that we receive x-th element of y-th row of z-th slice.

Now it should be clear, why you need additional variables and why it cannot be done with only single variable.

Bottomline: never use such solution, its a huge waste of memory. Instead, flatten your arrays and address by [z * xDim * yDim + y * xDim + x] or use jagged std::vectors or std::arrays.

Spook
  • 25,318
  • 18
  • 90
  • 167
  • He wanted to use standard library, just doesn't know it yet. – Bartek Banachewicz May 15 '13 at 07:46
  • Quite possible :) But there's also a chance, that this is a school task, which requires dynamic memory allocation. Pozdrawiam ;) – Spook May 15 '13 at 07:52
  • You're right, that's completely my bad. I added the necessary memory-freeing functions. If I didn't care, I could just use the code with the 3 different variables and finish this school assignment. Thing is, I really want to learn and understand this stuff. – Mechy May 15 '13 at 07:53
  • I could also use standard libraries, but I'm stubborn and like to cause myself pain by trying to figure out how to do it without them. I don't follow your explanation though. I think I'm following the same strategy as the code that does work: set pointers to point to a larger chunk of allocated memory that is all in one contiguous block, while keeping the advantage of using 3D array notation (phi[i][j][k]) – Mechy May 15 '13 at 08:24
  • Point is, if you are not programming on embedded SOCs with 1kB of RAM, you will have the standard library, because it's a part of language standard. One might say "I don't want to use structs or arrays, because I want to figure out how to do without them". IMHO you should learn how to write good code using basic building blocks, not try to write something that's neither good nor really educational. – Bartek Banachewicz May 15 '13 at 08:29
  • I think I finally get it. Thanks for the explanation. So basically, only one of my values is being used for each array. That is, phi[0] is a pointer to 16 cells. I have no way to access any of those cells but the first one... phi[0][0] is a pointer to another array of cells that I have no way to access. This is why I have to use 3 variables for a matrix as one contiguous block if I want to have it without libraries. Then again, aren't I making those "garbage" cells like phi[1] point to something that no longer makes them garbage? – Mechy May 15 '13 at 08:44
  • @spook I don't understand. Isn't that what my for loops currently do? I updated the code to communicate better on what those for loops are doing. – Mechy May 15 '13 at 08:54
  • This is not true. phi is array of 4 cells and you can access them by `phi[0]`, `phi[1]`, ..., `phi[3]`. `phi[0]` is an array of 16 cells and you can access them by `phi[0][0]`, `phi[0][1]`, ..., `phi[0][15]`. The problem is not that you cannot access these, but that you only initialize one of them and leave the rest uninitialized (but try to use them anyway) - I mean, phi[1] does not exists and is not allocated properly. Edited the answer. – Spook May 15 '13 at 08:57
  • Your loops doesn't *initialize* the arrays, they already try to *use* them. Look at the *Solution* section of my answer. This is what you should do *prior* to your loops for the segfault not to happen. – Spook May 15 '13 at 08:58
  • @Spook I'm pretty good at allocating jagged arrays. I'm not going for that though. I'm trying to setup arrays of pointers to point to a large chunk of allocated memory so I can just use 3D matrix notation on that guy. Does the code make a little more sense with the updates now? So for example, I'm having my first four elements of the phi[i] point to a chunk of data from phi[i][j] but offset a certain amount so as the array increments, the data is still aligned. I do the same thing with the elements from phi[i][j] – Mechy May 15 '13 at 08:58
  • @Spook it's ridiculous that the top code and the bottom code work though. If MY notation works for 2D notation, why would it not work for 3D notation? – Mechy May 15 '13 at 09:03
  • Awwww keeeey, I see now, what you're trying to do. Edited the answer, is it clear now? – Spook May 15 '13 at 09:10
  • You should have two different variables: one for the actual data and one for your "shortcut pointers" to the data. You try to store both data and pointers in the same array and that's what is causing the trouble. That's a very unusual solution though: you double the size of original array to store pointers to original array. It consumes a lot memory pointlessly, as you can simply use addressing: `[z * xDim * yDim + y * xDim + x]` – Spook May 15 '13 at 09:11
  • @Spook Ha ha! I think I see what you're getting at. I'm making phi[i] point to the wrong matrix, right? It'd work if I was doing 2D matrix notation because phi[i] would be pointing to the REAL data matrix. With the 3D matrix phi[i] is pointing simply to a matrix of pointers, which I DON'T want. I need it to point to phi[i][j] stuff. Also, yeah, I could probably just do the same stuff with a flattened matrix. I just don't want to use them. – Mechy May 15 '13 at 09:17
  • Everything you want to do is just damn wrong. – Bartek Banachewicz May 15 '13 at 09:26
  • @Bartek Banachewicz Yeah, I don't even make sense. My memory for my assignment phi[i] just gets overlapped when I do my assignment for phi[i][j] to something. It's just all messed up like my understanding of this whole thing. What a colossal waste of time. – Mechy May 15 '13 at 09:38
  • 1
    I've edited my post the final time. I hope, that it should explain everything to you now. – Spook May 15 '13 at 10:00
  • @Spook thanks! Man, I have learned to stay away from 3D matrices. It's only 1D (and 2D since my solution works for 2D although it gives memory waste) for me from now on unless for some reason I really need a 3D matrix to accomplish some hell of a task. I've edited the top post to show a solution to using 3D matrix notation for convenience as desired as well for a 1D matrix SUPER EASILY! – Mechy May 15 '13 at 10:19
  • I guess, that it was the most toughly earned accepted answer in my SO history :) – Spook May 15 '13 at 10:21
  • As an author of [original 3-d matrix code](http://stackoverflow.com/a/16555923/1734130), I should have added similar explanation to my implementation as you did. I don't agree that this is "huge" waste of memory - jagged arrays waste **much** more. Asker insisted to use unchanged `a[i][j][k]` syntax, and be memory efficient. This is the only reasonable implementation that can fulfill these requirements. Also note that my first suggestion was to use 1-d array appropriately. – mvp May 15 '13 at 16:12
  • Why would jagged arrays waste much more memory? They would require dimZ * dimY pointers and dimX * dimY * dimZ doubles. Your solution requires dimX + dimX * dimY pointers and dimX * dimY * dimZ doubles. And for the problem you stated, maybe one may write a wrapper class with two proxy classes with overloaded [] operators? Effectively that would use not much than a couple of pointers, but on the other hand also would be much less time-efficient than direct array access. I have to admit, that your solution is quite tricky and it took a moment to figure out what points to what ;) – Spook May 15 '13 at 17:17
  • BTW, feel free to copy my explanation to the post you linked, it'll save you time. – Spook May 15 '13 at 17:48
  • I just want to thank both of you for all the help. You both really increased my understanding of c++. – Mechy May 17 '13 at 16:44