-1

What is the equivalent matrix-like C-array of a nested std::vector (for C and C++ interop)?

For example, if one wanted to treat std::vector<std::vector<int>> as some kind of int arr[n][m], where n is the dimension of the outer vector and m of the inner vector, then what structure would one use in C?


This is motivated by wanting to have a similar correspondence between matrices in C and C++ as for vectors in:

https://stackoverflow.com/a/1733150/4959635

mavavilj
  • 129
  • 13
  • 1
    Can I ask why you want to do this? – Nir Friedman Jun 28 '15 at 01:35
  • 2
    Your use of the word "dimension(al)" in the question is confusing. By dimension, do you mean size, or [dimensionality](https://en.wikipedia.org/wiki/Dimension)? – Sam Estep Jun 28 '15 at 01:39
  • What function is this that needs an N-dimensional C-array? Usually in C, even if you want to pass in an N-dimensional array, you actually are passing a pointer to the beginning of a block of contiguous memory that holds the data. Are you sure that's not the case here? Or can your C function take non-contiguous arrays? – Nir Friedman Jun 28 '15 at 01:41
  • Size, but these do get mixed. – mavavilj Jun 28 '15 at 01:43
  • 1
    Create N-1 layers of helpers of arrays of pointers. – Cheers and hth. - Alf Jun 28 '15 at 01:43
  • @NirFriedman : So how do I pass the N starting addresses from the N-dimensional std::vector then? For N=1 it's &vec[0] or I believe vec.data() as well. – mavavilj Jun 28 '15 at 01:45
  • 2
    My point is that most C functions would idiomatically take a single pointer to the block of data, this is both simpler and more efficient as all the data is contiguous. If that's the case, I can offer some better alternatives. What is this function that takes an N-dimensional array? Is it code controlled by you? Is it public somewhere, can you link me the documentation? – Nir Friedman Jun 28 '15 at 01:48
  • @NirFriedman : It's a function that I'm just implementing myself, but it makes more sense to use fixed-length arrays than vectors in it. But I needed the std::vector, because my input data is variable-length before passing it into the function (so I can't initialize a C-array with the correct length). – mavavilj Jun 28 '15 at 01:50
  • What benefit are you getting by using fixed length arrays after your data is coming in as a vectors? If you're not adding to the vector anymore, you don't need to worry the resize time factor, and it's contiguous as well already. Nonetheless, keep in mind you can use reserve on a vector if somehow you knew the size at compile time for those vectors (which you kind of hint at). In c++11, you can use vector::data() to get C array pointer though nonetheless. – Joe Jun 28 '15 at 01:57
  • If you're talking about a stack C array, the size has to be known at compile time. So you'll never be able to initialize such an array from a vector. If you're talking about C dynamic arrays, you may as well just pass the vector. Honestly if you're writing C++ there's no reason why you'd want to take this C-esque approach. – Nir Friedman Jun 28 '15 at 01:58
  • @Joe: Because my processing in the function has to be done at specified sized arrays (or buffers). The size of the buffer is fixed and has to be known by that time, but the input data that is used to fill that buffer comes in variable sized chunks. – mavavilj Jun 28 '15 at 02:03
  • Also, do you really need the generality of saying N-dimensional? To make this work well will require getting into more advanced concepts, isn't 2 or 3 dimensional ok? – Nir Friedman Jun 28 '15 at 02:03
  • @NirFriedman: 2 is enough for me, but I just made the question a bit more general. – mavavilj Jun 28 '15 at 02:04
  • Also I really do need the C-arrays (or a 2D pointer) from the vector, because inside my own function I'm using a library function that takes in void *, which would need to be the inner vectors (as void *). – mavavilj Jun 28 '15 at 02:09
  • That does not mean you need C-arrays. You can get a raw pointer from the inner vectors. – Nir Friedman Jun 28 '15 at 02:12
  • Is it &vec.at(outerindex)[0] then for the 2D vector case? Or vec.at(outerindex).data()? – mavavilj Jun 28 '15 at 02:16
  • The original motivation for this question was to understand the conventions of writing C and C++ along-side, but C not having std::vector. In case one wanted to "port" C++ to C. – mavavilj Aug 23 '22 at 11:48

2 Answers2

2

Based on additional information in the comments, let me suggest you do something like this instead:

class TwoDimVector {
 public:
  TwoDimVector(int num_cols, int num_rows)
      : m_num_cols(num_cols)
      , m_num_rows(num_rows)
      , m_data(m_num_cols * m_num_rows, 0)
  { }

  int & ix(int row, int col) {
     return data[num_cols * row + col];
  }


  const int m_num_rows;
  const int m_num_cols;
 private:
  std::vector<int> m_data;
}

When you do nested vectors, there's a lot of extra work happening. Also, with nested vectors, the data is not contiguous, making it hard to work with any C-apis. Notice with this data structure, the size is fixed at construction time and accessible. This is designed to be row contiguous, so for C interoperability you can access extra raw pointers like so:

TwoDimVector tdv(4,3);
int * raw = &tdv.ix(0,0);
int * raw_second_row = &tdv.ix(1,0);

Just note: if you pass this into a function, be sure to pass by reference:

void do_work(TwoDimVector & tdv) {
  ...
}

If you don't pass by reference, it will copy everything, which is a bunch of (typically unnecessary) work.

Nir Friedman
  • 17,108
  • 2
  • 44
  • 72
  • Is that also indexable in subarrays? Given that the ix function takes a col parameter as well. I personally only need whole rows. – mavavilj Jun 28 '15 at 02:19
  • I'm not sure what you mean by indexable by subarrays means, but I showed you how to extract a pointer to a row, which I thought is what you needed. – Nir Friedman Jun 28 '15 at 02:23
  • That could I get a part of a column as well using that code? What about the Add function for this class. Also any idea if this kind of class could be found somewhere already implemented? – mavavilj Jun 28 '15 at 02:31
  • I don't know what you mean by add function. A column will not be contiguous (rows and columns can't both be contiguous), so I'm not sure what you mean by get. You could look at matrix libraries for C++, but that generally comes with a lot of other stuff. You could also just use a std::vector and call the ix function yourself to get the right thing, but more bug prone. Anyhow, I think the scope of this question is creeping, I think I've taken a good chunk of time and tried to answer your question. I think you maybe need to digest some of the things written here. – Nir Friedman Jun 28 '15 at 02:45
  • "Adding function": std::vector has insert() and push_back(). – mavavilj Aug 10 '22 at 09:54
0

Maybe, this code

  void translate(const vector< vector >& vec){

int m = vec.size(), n = 0;

for (vector<int>& deep : vec) // search maximum size if nested vectors
{
    if (deep.size() > n)
        n = deep.size();
}

int arr[m][n];

m = n = 0;
for (vector<int>& deep : vec){
    for (int& x : deep)
    {
        arr[m][n] = x;
        ++n;
    }

    ++m;
}

// So, I really don't know how you can return this array :( }

You see, it code is BAD, you mustn't do it !!!
If you writing on C++ you should using std::vector - it is easier. C-like arrays is heritage from C, you shouldn't using they

vlad4378
  • 803
  • 1
  • 9
  • 21