Madeleine P. Vincent
Madeleine P. Vincent

Reputation: 3621

C++ - Need to pass a 2D array, but must be dynamically sized

I am using a C++ library that requires that I pass it a 2D array. Their code example gives a statically sized array like this:

double data[][2] = {
  { 10, 20, },
  { 13, 16, },
  { 7, 30, },
  { 15, 34, },
  { 25, 4, },
};

But I need to pass run-time sized data. So I was attempting to do this:

  // unsigned numBins  is passed in to this function and set at run time

  double** binData = new double*[numBins];
  for(unsigned i=0; i < numBins; ++i) {
    binData[i] = new double[2];
  }
  //Set the data with something like
  //   binData[7][0] = 10;
  //   binData[7][1] = 100;

  //Later, diligently delete my data...

However, this fails in the library I am using. It ends of graphing some garbage numbers.

I understand that arrays are not pointers. And the library may be getting confused doing a "sizeof" somewhere.

If I am unable to change this library (it's 3rd party), how do I go about passing it dynamically sized data?

Thanks, Maddie.

Upvotes: 0

Views: 196

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275405

Probably the API expects a pointer to the first element of what it assumes is a flattened representation of a 2D array.

So the easy approach is as follows:

template<typename T>
struct FlatVectorAs2D {
private:
  size_t width;
  size_t height;
  std::vector<T> flat_vec;
public:
  std::vector<T>& base() { return flat_vec; }
  std::vector<T> const& base() const { return flat_vec; }
  size_t w() const { return width; }
  size_t h() const { return height; }
  T* operator[]( size_t index1 ) {
    return &flat_vec[index1*height];
  }
  T const* operator[]( size_t index1 ) const {
    return &flat_vec[index1*height];
  }
  FlatVectorAs2D( size_t w = 1, size_t h = 1 ):width(w), height(h) {
    flat_vec.resize(w*h);
  }
  void resize( size_t w, size_t h ) {
    width = w;
    height = h;
    flat_vec.resize(w*h);
  }
  T* raw() { return flat_vec.data(); }
  T const* raw() const { return flat_vec.data(); }
};

Use:

void api_function(double* d);
int main() {
  size_t width = 50;
  size_t height = 100;
  FlatVectorAs2D<double> buffer( width, height );
  buffer[0][1] = 1.0;
  api_function( buffer.raw() );
}

naturally this will depend on how exactly the API works.

But if my guess is right, this will help.

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477060

Try this:

typedef double two_doubles[2];

int main()
{
    two_doubles * p = new two_doubles[300];

    // ...

    delete[] p;
}

Now p points to the first subarray of an array of 200 units of two doubles. That is, p[i] is a double[2], and p[i][0], p[i][1] are its member elements.

(Even better to use std::unique_ptr<two_doubles[]> p(new two_doubles[300]); and forget about the memory management.)

Upvotes: 0

Related Questions