Correct way to write a function that return an n-dimensional array of TH1 objects


I’m trying to write a function that return an array of TH1D histograms.
I follow a post on stackoverflow, which recommended using malloc to create the array of histograms. I follow the instruction and my code works.
The code I wrote is as follow:

TH1D** *array_of_hists( )
	TH1D** *hist = ( TH1D*** )malloc( sizeof(TH1D**)*2 );
	for ( int i=0; i<2; i++ )
		hist[i] = ( TH1D** )malloc( sizeof(TH1D*)*5 );
		for ( int j=0; j<2; j++ )
			std::string hist_name = Form ( "hist_%d_%d", i, j );
			hist[i][j] = new TH1D( ), "", 20, -5, 5 );
			hist[i][j] -> FillRandom( "gaus", 10000 );
	return hist;

int test_TH1_array( )
	system( "mkdir -p Plot" );
	TH1D** *hist = array_of_hists( );
	for ( int i=0; i<2; i++ )
		for ( int j=0; j<2; j++ )
			TCanvas *canvas = new TCanvas( "canvas", "", 600, 400 );
			canvas -> cd( );
			hist[i][j] -> SetLineColor( kOrange+7 );
			hist[i][j] -> SetLineWidth( 2 );
			hist[i][j] -> Draw( "hist" );
			canvas -> SaveAs( Form( "Plot/plot_%d_%d.png", i, j ) );
			delete canvas;
	return 0;

Though the program runs fine, I still didn’t understanding my code well. When I remove the asterisk(s) in the malloc function:

TH1D** *hist = ( TH1D*** )malloc( sizeof(TH1D)*2 );

It still works, and the result looks ok, although I expected an seg fault from the missing asterisks.
So, I want to ask:

  1. Why the missing asterisk does not affect my result?
  2. Which is the correct way to define the array of histogram using malloc?

Thank you very much,

ROOT Version: ROOT6.24/00
Platform: Ubuntu 18.04
Compiler: Not Provided

Hi @LongHoa,

I guess that you are referring to a couple of asterisks you removed in sizeof(TH1D**). The rest of the explanation will just assume that.
In the code above, the original line allocates enough space on the heap (via malloc()) to hold an array of 2 pointers. If you remove the those, you will allocate space for storing 2 TH1D instances. As long as the size of a TH1D object is greater than the size of a pointer -which it certainly is-, the allocation will be large enough for the expected usage. Therefore, in this case, you are reserving slightly more memory (while using just a few bytes at the beginning of the region).

Replied above; no expected segfault, as you are just using the first few bytes of a larger allocation; no unintended misuse or data corruption.

The code above is actually creating an array of pointers to arrays, which is not the same as a n-dimensional array in row-major (C) order.
I would simplify the code a lot -which also makes it more efficient-, by allocating space for N objects, and being N the total number of TH1D objects (i.e., a linear array).


1 Like