Saving an array of character strings in a root tree

G’day,
I’m trying to save a variable number of strings in a branch of a root tree. I’m not having much luck. I don’t care whether I save them as const char*, TStrings, or even TObjString (whatever I can get to work).

Here’s what I tried so far:

// for saving the root file
void saveStringsInRoot()
{
   char names[10][100] = {"peter", "bob", "fred", "michael"};
   int num = 4;
   for (int loop = 0; loop < num; ++loop)
   {
      cout << loop << ") " << names[loop] << endl;
   }
   cout << "Creating new name tree" << endl;
   tree = new TTree("names", "L1 Trigger Names");
   tree->Branch("num", &num, "num/i");
   tree->Branch("names", names , "names[num]/C");
   tree->Fill();
   tree->ls();
   TFile file ("test1.root", "RECREATE", "XMon Root file");
   tree->Write();
   file.Close();
}

and

// for reading in the root file
void readStringRootFile()
{
   TFile file ("test1.root");
   TTree *tree = (TTree*) file.Get("names");
   tree->ls();
   Long64_t numEntries = tree->GetEntries();
   cout << "numEntries " << numEntries << endl;
   int num;
   char names[10][100];
   tree->SetBranchAddress ("num", &num);
   tree->SetBranchAddress ("names", names);
   tree->GetEntry(0);
   cout << "num of names " << num << endl;
   for (int loop = 0; loop < num; ++loop) 
   {
      cout << loop << ") " << names[loop] << endl;
   } // for loop
   
}

Here’s the output I get running on root 4.02/00 on cygwin (I get equivalent output on root v4_00_08 on RH7.3:

cplager@PointyIII> root -l -q saveStringsInRoot.c
root [0] 
Processing saveStringsInRoot.c...
0) peter
1) bob
2) fred
3) michael
Creating new name tree
OBJ: TTree      names   L1 Trigger Names : 0 at: 0x10f82f40
************************************
*    Row   *       num *     names *
************************************
*        0 *         4 *     peter *
************************************
cplager@PointyIII> root -l -q readStringRootFile.c
root [0] 
Processing readStringRootFile.c...
OBJ: TTree      names   L1 Trigger Names : 0 at: 0x1105ad00
numEntries 1
num of names 4
0) peter
1) 
2) ¸
3) 

Where I would have expected the four names, not just the first one.

So…

What am I doing wrong and how can I fix this?

Cheers,
Charles

You have several solutions, eg
TObjArray of TObjString
std::vector

Rene

The choice of using std::vector seems very attractive. How do I tell root (i.e. what is the equivalent of

tree->Branch("names", names , "names[num]/C");
)?

Cheers,
Charles

With ROOT 4.03/02 you can do:

std::vector<string> *mystrings; tree->Branch("names",&mystrings); With older version of ROOT, you have to embedded the vector in another class and create a branch using this class.

Cheers,
Philippe.

Hi Philippe,

Just because I’m curioius…

   std::vector<string> *mystrings;
   tree->Branch("names",&mystrings); 

mystrings is a pointer to a vector. But when setting up the branch, instead of passing in a pointer to (or address of) a stl vector (like you would for floats, etc), you pass in a pointer to a poiinter to an stl vector. What’s going on here?

Charles

p.s. You mentioned that this will work on Root version 4.03/02. Is that the earliest version I could try?

Hi,

Yes storing a STL container as a top level object in a branch is only supported in ROOT 4.03/02 and above.

This is because numerical types and objects are treated differently in a TTree. For a numerical type, you can use the ‘leaflist’ method which expects the address where to store/retrieve the data. For objects, TTree expect the address of a pointer so that it can (when needed) return to the user the address of the memory it allocated.
Note that a more familiar syntax is:

tree->Branch("names","vector<string>",&mystrings);

Cheers,
Philippe.

Note that ROOT 4.03/02 is now available on the web

Rene