0

In C++ in ROOT (the CERN language), I have declared a 2D array of histograms:

TH1F *hist[xlen][ylen];

where xlen and ylen are not variable-length; I assign them values in my code.

I would like to pass this 2D array into a function. I'm having trouble specifying the input parameter, however. Can someone help me out?

For an example, I can pass a 1D histogram (TH1F *hist[length];) with a function like,

void func(TH1F** Hist) {
  cout<<Hist[0]<<endl;
}

Please note that although my 2D histogram has a definite size (i.e. xlen, ylen), as defined in my code, I do not want the function to be limited to arrays of a single size.

Dan
  • 143
  • 6
  • 1
    Have you tried the solutions from [here](https://stackoverflow.com/questions/8767166/passing-a-2d-array-to-a-c-function)? – NathanOliver Aug 17 '17 at 15:04
  • 1
    Possible duplicate of [C -- passing a 2d array as a function argument?](https://stackoverflow.com/questions/6862813/c-passing-a-2d-array-as-a-function-argument) – Noam Ohana Aug 17 '17 at 15:08
  • are `xlen` and `ylen` constants in the sense that you could define them like `#define xlen 10`? – Stephan Lechner Aug 17 '17 at 15:10
  • @stephan-lechner: I just define them differently for arrays with different purposes. i.e. `TH1F *hists1[5][10]` and `TH1F *hists2[3][5]`, etc. @n-o and @nathanoliver: it's not quite the same because the histograms are declared as pointers, I believe – Dan Aug 17 '17 at 15:12
  • _"I do not want the function to be limited to histograms of a single size."_ You mean that every row (histogram) could have different size? Am i understanding right? – kocica Aug 17 '17 at 15:15
  • @filip-kočica: sorry I mean a regular X by Y rectangular histogram. Answers to similar questions have suggested using a parameter with the second index specified already. For example, something like `void func( TH1F** hist[5])` for arrays of length X by 5. Since my arrays might differ in size, I would like the function to suffice for all of them. – Dan Aug 17 '17 at 15:17
  • @filip-kočica It doesn't seem to work. I'm trying `void hist2D(int C, int R, TH1F* hist[C][R])` and calling it with `hist2D(360, 171, h)`. The error is: _no known conversion from 'TH1F *[360][171]' to 'TH1F *(*)[R]' for 3rd argument_. – Dan Aug 17 '17 at 15:26
  • _"In C++, variable length arrays are not legal. G++ allows this as an "extension"_ Didnt notice its c++ taged. Sorry. We have to pass pointer to pointer and allocate it on heap, if you want to pass arrays with different sizes. Does it allow you to use _dynamic storage duration_ ? Or you have to use automatic arrays ? – kocica Aug 17 '17 at 15:27
  • @filip-kočica It's not variable length. My arrays are given a definite size in my code before compilation. I just want the function to not be limited to a specific size. – Dan Aug 17 '17 at 15:29
  • @NO that question is C, this one is C++. I don't think the top answer at that link even works in C++. – Mark Ransom Aug 17 '17 at 15:42

4 Answers4

0

If you want to use the same function for different dimensions within the same program, the only way I see is to pass a pointer to the first element of the array together with the dimensions and then calculate each index on your own, i.e. by current_row_index * column_size + current_column_index:

void func(int rows, int columns, int **hist) {

    static int arr[10] = {0,1,2,3,4,5,6,7,8,9};

    for(int r=0; r<rows; r++) {
        for(int c=0; c<columns; c++) {
            int* aPtr = &arr[(r*columns+c)%10];
            hist[r*columns + c] = aPtr;
            cout << *hist[r*columns + c] << " ";
        }
        cout << endl;
    }
}

int main() {


    int *a20x10[20][10] = {};
    int *a5x3[5][3] = {};

    func(20,10,&a20x10[0][0]);
    func(5,3,&a5x3[0][0]);

    return 0;
}
Stephan Lechner
  • 33,675
  • 4
  • 27
  • 49
0
/*But first of all you want to pass by reference, so a 
* more correct function call might be:
*/

void Call(TH1F **Hist, size_t size_x, size_t size_y);

/* allows changing hist or setting to NULL
 * in function
 */
void Call2(TH1F ***Hist, size_t size_x, size_t size_y);

/* with a call like */

int main(void)
{
    TH1F *hist[xlen][ylen] = NULL;

    /* malloc here/memset hist */

    Call(*hist, xlen, ylen);
    Call2(hist, xlen, ylen);
    return (0);
}
Nathan P
  • 24
  • 3
0

You can do this with a template function. The template will automatically pick up the dimensions of the array.

template<int C, int R>
void func(TH1F* (&hist)[C][R])
{
    cout << hist[0][0] << endl;
}
Mark Ransom
  • 271,357
  • 39
  • 345
  • 578
  • calling it by doing `func(hist)` gives _error: no matching function for call to 'func'._ _note: candidate template ignored: could not match 'TH1F *' against 'TH1F *'_ – Dan Aug 17 '17 at 19:37
  • The only thing I can think of is there's a difference between using TH1F as a struct versus the actual class implementation of TH1F in ROOT. Other than that, I'm not completely sure why it fails for me. – Dan Aug 17 '17 at 19:45
0

I managed to get it to work trivially by circumventing the issue: Using a vector of vectors instead of a 2D array.

The answer by Stephan seems the closest to solving it as intended, but did not work. It is also a bit too complicated for me to know how to adjust the code to make it work.

Dan
  • 143
  • 6