views:

145

answers:

3

Edit: Thank you all very much for your help. Now I feel that I'm really stupid and I am so sorry to waste your time. After implementing James Hopkin' suggestion, I still get the warnings of "invalid name 'null'", which is much better than those weird characters. Then, I went back and read the library document again, and it turns out that for that particular function, it's argument should have one more element of non-NULL string than the size of aNames. That additional string has some other purpose. After adding one more string, the code runs fine. It's all my fault, and I am so sorry.

Original post:

Hi,

This is my first post so please be nice. I searched in this forum and googled but I still can not find the answer. This problem has bothered me for more than a day, so please give me some help. Thank you.

I need to pass a vector of string to a library function foo(char const *const *const). I can not pass the &Vec[0] since it's a pointer to a string. Therefore, I have an array and pass the c_str() to that array. The following is my code (aNames is the vector of string):

const char* aR[aNames.size()];

std::transform(aNames.begin(), aNames.end(), aR, 
                boost::bind(&std::string::c_str, _1));
foo(aR);

However, it seems it causes some undefined behavior:

If I run the above code, then the function foo throw some warnings about illegal characters ('èI' blablabla) in aR.

If I print aR before function foo like this:

std::copy(aR, aR+rowNames.size(), 
          std::ostream_iterator<const char*>(std::cout, "\n"));
foo(aR);

Then, everything is fine. My questions are:

  1. Does the conversion causes undefined behavior? If so, why?

  2. What is the correct way to pass vector of string to foo(char const *const *const)?

Thank you very much for your help!

+1  A: 

Well it's seems right to me. c_str create a null terminated array of char that is constant until the next non-const string operation. You store the c_str pointers in a const char* array.

I'm no boost specialist so the problem might be there, but my guess is that your strings in the vector are in an encoding that is incompatible with the one expected in function foo.

Check your code from the encoding point of view.

my2c

neuro
+5  A: 

Since foo only takes a pointer, my wild guess is that it requires a NULL-terminated array. Allocate an extra element for aR and assign NULL to it.

My suggestion would be:

std::vector<const char*> c_strings;
c_strings.reserve(aNames.size() + 1);

std::transform(
    aNames.begin(), aNames.end(),
    std::back_inserter(c_strings), 
    boost::bind(&std::string::c_str, _1)
    );

c_strings.push_back(0);
foo(&c_strings[0]);
James Hopkin
+1 Good guess. Indeed, the only possibility to find an array size for `foo` function is to find the NULL pointer.
Kirill V. Lyadvinsky
Yes, good guess ! Unless if the foo function signature is not the real one. @user347208 : Is that the exact function signature ?
neuro
Thank you very much for your help! @neuro: the exact function signature is int foo(const char * filename, char const *const *const rowNames, char const *const *const columnNames). However, as what I said in my edition, I'm so sorry that I didn't read the documents carefully and wasted your time. Anyway, thank you all very much for your help!
EXP0
+1  A: 

Try this:

std::vector<char*> arr(aNames.size()+1); 
for(size_t i = 0; i < aNames.size(); ++i) 
    arr[i] = aNames[i].c_str();
arr[arr.size()-1] = NULL; // just in case
foo(&arr[0]);
Remy Lebeau - TeamB
Won't compile - `c_str` returns a `const char*`
James Hopkin
Ok. Changing the vector to hold "const char*" elements compiles for me now.
Remy Lebeau - TeamB