2

I have a float array. Since i deal with big data > 10 GB i want to allocate some space But how do i write and read into this data ? I have to say, i'm a matlab coder, and have no idea how to do this in c++.

// allocating space
float *buffnew = new float[size_x*size_y*size_z];
// write
**buffnew[x][y][z] = 1.1f;
// read
prediction = **buffnew[x][y][z];

This does not work.The error i get is:

error: subscripted value is not an array, pointer, or vector

edit : I just see my error. I used an 1D array to allocate ( on the heap, because of the big data ) and then used a 3D to access it.

4
  • std::array<std::array<std::array<float ,size_z>, size_y>, size_x> Commented Dec 4, 2013 at 13:29
  • 1
    I recommend you to first do basic pointer operations and understand how they really work. Then continue to 2d and then 3d. If you do this, you will automatically get the answer. Commented Dec 4, 2013 at 13:29
  • @phoxis yeah.. maybe you're right. Can you point me to a good tutorial ? Commented Dec 4, 2013 at 13:32
  • @StoryTeller: If the sizes are compile-time constants; and you'll still need some kind of dynamic allocation to keep the large object off the stack. Commented Dec 4, 2013 at 13:42

5 Answers 5

4

C++ doesn't provide convenient syntax for dynamic multi-dimensional arrays. You've allocated a one-dimensional array, so you'll need to do arithmetic to access it, for example:

buffnew[x*size_y*size_z + y*size_z + z] = 1.1f;

It might make sense to wrap the array in a class, with an accessor function to do the arithmetic:

template <typename T>
class array3d {
public:
    array3d(size_t x, size_t y, size_t z) : array(x*y*z) {}

    T & operator()(size_t x, size_t y, size_t z) {
        return array[x*size_y*size_z + y*size_z + z];
    }

    T const & operator()(size_t x, size_t y, size_t z) const {
        return array[x*size_y*size_z + y*size_z + z];
    }

private:
    std::vector<T> array;
};

array3d<float> buffnew(size_x, size_y, size_z);
buffnew(x,y,z) = 1.1f;
prediction = buffnew(x,y,z);

By using std::vector rather than an evil pointer, the class is copyable, and will automatically free the memory on destruction.

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

7 Comments

Now that is an answer (in addition to the other vector answer), apart from all this new float[][][] rubbish and the even worse dynamic arrays of pointers to dynamic arrays of pointers to dynamic arrays.
Woow. You nailed it. Thank you ! i will use std::vector.
Since you wrap the vector you could also add bounds-checked indexing, by using array.at(xsize_ysize_z + ysize_z + z) instead of array[xsize_ysize_z + ysize_z + z]
@Silas: Perhaps; but that should be optional (e.g. via separate at functions), since you don't want to pay the price of the check when it's not necessary. It would also incur the cost of storing the sizes, if you want to check the bounds properly.
@MikeSeymour I like to build it into objects. Bounds checking is very good for correctness, and very easy to remove later if it turns out to be an efficiency problem. Btw you will always need the dimension sizes.
|
2

Assuming you have enough ram, you use a vector

#include <vector>
std::vector<float> values;
values.resize(size_x * size_y * size_z);

values[z + y*size_z + x*size_y*size_z] = 1.1;
prediction = values[z + y*size_z + x*size_y*size_z];

A completely different approach that will give a nice (x,y,z) interface is to use lambda functions and closures.

#include <vector>
#include <functional>

template<typename T>
std::function<T&(std::size_t, std::size_t, std::size_t)> 
vector3d(std::size_t size_x, std::size_t size_y, std::size_t size_z) {
    std::vector<T> values(size_x*size_y*size_z);
    return [values, size_x, size_y, size_z](std::size_t x, std::size_t y, std::size_t z) mutable -> T&
    {
    return values.at(z + y*size_z + x*size_y*size_z);
    };
}

Notice that the lambda captures the allocated vector by value. This function can then be used like this

std::size_t size_x = 10, size_y = 20, size_z = 30;
auto array = vector3d<float>(size_x, size_y, size_z);

std::size_t x = 3, y = 3, z = 3;
f(x,y,z) = 12.12;
auto prediction = f(x,y,z);

4 Comments

If you don't try a deque. What's your last line doing?
The last line does assignment, I just forgot to finish it :)
If C++11 you can use std::array
@mathk Yet that is in no way equivalent to a vector as it requires compile-time constant sizes and sufficient stack memory.
0

You do not need to use

**buffnew[x][y][z]

From the read type, i think you want a three dimensional array. For that, declare

float *buffnew = new float[size_x][size_y][size_z];
buffnew[x][y][z] = 1.1f; //write
prediction = buffnew[x][y][z]; //read

This is how it is done in C++

2 Comments

float buffnew = new... Shouldn't there be some stars in there?
Of course only if two of those sizes are compile-time constants.
0

You can either make a multi dimensional array

float ***buffnew = new float**[size_x];
for(unsigned int i = 0; i < size_x; ++i) {
  buffnew[i] = new float*[size_y];
  for(unsigned int j = 0; j < size_y; ++j) {
    buffnew[i][j] = new float[size_z];
  }
}

Or make a one dimensional array linearly containing all the elements, but then you would have to calculate the right index from the actual x, y and z.

Comments

0

I think this is what you want:

float *buffnew = new float[size_x][size_y][size_z];
buffnew[index1][index2][index3] = 1.1f;
[...]
prediction = buffnew[index1][index2][index3];

That is a standard way of handling a 3-dimensional array in C++.

Or you could use std::vector.

1 Comment

Of course only if two of those sizes are compile-time constants.

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.