What is the easiest way to initialize a 2d array from a vector of strings?

124 Views Asked by At

I have:

vector<string> myVector = {0};

myVector.push_back("first");
myVector.push_back("second");

char *list[] = ????

I want it to be initialized like if I was doing this

char *list[] = { "first", "second", NULL };

I know I can start allocating memory based on the size and of the vector and the size of the longest string in the vector (list[v.size()+1][longest_string_in_vector]) but I wanted to see I'm not thinking of something that might be easier/faster.

2

There are 2 best solutions below

1
On BEST ANSWER

If the legacy code requires a char **, then to create a variable list, you can create a vector as you initially are doing in your question.

After that, create a std::vector<char *>, where the pointers are pointers within the vector for each item. Of course, you have to ensure that the vector doesn't go out of scope or is resized. It has to be fully "set up" before creating the std::vector<char *>.

In addition, since you are certain that the legacy function does not attempt to alter the strings sent to it, we should take away the "constness" of the strings.

#include <vector>
#include <string>
#include <iostream>

void legacy_function(char **myList) 
{
     for (int i = 0; myList[i]; ++i)
          std::cout << myList[i] << "\n";
}

using namespace std;
int main()
{
    vector<string> myVector;
    myVector.push_back("first");
    myVector.push_back("second");
    //...
    // create the pointer vector
    vector<char *> myPtrVector;
    // add pointer to string to vector
    for (size_t i = 0; i < myVector.size(); ++i)
       myPtrVector.push_back(const_cast<char*>(myVector[i].c_str()));
    // stick the null at the end
    myPtrVector.push_back(NULL);
    // ...
    // call legacy function
    legacy_function(&myPtrVector[0]);
}  

Basically, we created the strings in a vector, and created another vector that stores pointers to the strings.

Note that the function legacy_function takes a char **, and all we need to do is pass it the address of the first element in our pointer vector.

Live Example: http://ideone.com/77oNns

Edit: Rather than having the code strewn in different areas of your program, a better approach in terms of code organization is to encapsulate the creation of the array:

#include <vector>
#include <string>

class CharPtrPtr
{
   std::vector<std::string> m_args;
   std::vector<char *> m_argsptr;

   public:
       void add(const std::string& s) { m_args.push_back(s); }

       char ** create_argsPtr() 
       { 
          m_argsptr.clear();
          for (size_t i = 0; i < m_args.size(); ++i)
             m_argsptr.push_back(const_cast<char*>(m_args[i].c_str()));
          m_argsptr.push_back(NULL);
          return &m_argsptr[0]; 
       }

       char **get_argsPtr() { return m_argsptr.empty()?NULL:&m_argsptr[0]; }

       void clear_args() { m_args.clear(); m_argsptr.clear(); }
};


#include <iostream>

void legacy_function(char **myList) 
{
    for (int i = 0; myList[i]; ++i)
        std::cout << myList[i] << "\n";
}

int main()
{
    CharPtrPtr args;
    args.add("first");
    args.add("second");
    legacy_function(args.create_argsPtr());
}     

Live Example: http://coliru.stacked-crooked.com/a/834afa665f054a1f

2
On

I tried these two ways,

1.Initialize manually

char *list[] = { (char*)&myVector[0][0], (char*)&myVector[1][0] };

2.Initialize in a loop

char **list2 = new char*[ myVector.size() ];
for ( unsigned int i = 0; i < myVector.size(); ++i ) {
    list2[ i ] = (char*)&myVector[ i ][0];
}

However these lists only have pointers to the each string in the vector and don't actually have a copy. If you change the strings, you'll see the changes from the lists. But if you empty the vector then the lists will have a dangling pointer.

3.If you want a copy of the strings then,

char **list = new char*[ myVector.size() ];
for ( unsigned int i = 0; i < myVector.size(); ++i ) {
    list[ i ] = new char[myVector[i].size()+1];
    strcpy( list[ i ], &myVector[i][0] );
}

I wouldn't write this code but, there you go..