C++: vector<string> to char** [duplicate] - c++

This question already has answers here:
convert vector<string> into char** C++
(4 answers)
Closed 7 years ago.
I am converting my app to be able to be used as a library. For this purpose, I want to offer the possibility to pass a vector of strings to the library's default run routine.
The problem I am running into, is actually creating the char**. This is my current implementation, commented out in the source since it isn't working:
IceTea* IceTea::setupCli(vector<string> strings) {
int argc=strings.size(), i=0;
char* argv[argc];
vector<string>::iterator it;
for(it=strings.begin(); it != strings.end(); ++it) {
argv[i++] = (char*)it->c_str();
}
// Pass the char** to the original method.
return this->setupCli(argc, argv);
}
The error I get:
src/IceTea.cpp:132:18: error: no matching member function for call to 'setupCli'
return this->setupCli(argc, argv);
~~~~~~^~~~~~~~
src/IceTea.h:44:13: note: candidate function not viable: no known conversion from 'char *[argc]' to 'const char **' for 2nd argument
IceTea* setupCli(int, const char**);
^
src/IceTea.cpp:124:17: note: candidate function not viable: requires single argument 'strings', but 2 arguments were provided
IceTea* IceTea::setupCli(vector<string> strings) {

I am afraid you cannot convert a vector<string> to char** in constant time. A vector<string> can be converted to string* pretty easily, and string can be converted to char* pretty easily, but vector cannot be converted to char**. Actually, this is a problem very similar to why an int[10][20] cannot be trivially converted to an int**.
Now, if you absolutely have to do this, then
vector<char*> pointerVec(strings.size());
for(unsigned i = 0; i < strings.size(); ++i)
{
pointerVec[i] = strings[i].data();
} //you can use transform instead of this loop
char** result = pointerVec.data();
The main problem with your code is that you're using c_str which returns a const char *. Note that I'm using the data() member function instead, which returns the non-const pointer. Another difference between your attempt and my suggestion is that you're using an array of a length which is not a constant expression. That is illegal in standard C++. I used a vector instead and later converted it to a pointer with the same data() function.

Related

Conversion of std:string to char* [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm trying to convert a result string that I get by doing some data manipulation, eg:
std::string result = std::string(/* num_max */, '0').append(myDataModule->getId().c_str());
I'm getting an id from getId() (which returns an AnsiString) on my TDataModule, converting that to a std::string using AnsiString::c_str(), and appending that with zeros on the left (spaces that will remain) to my result string.
I need to use the value of result in a function that receives a char *:
void receiver(char * data, int num){
... <- A lot of code here
if( data != NULL )
{
strcpy( rdData, data); <-- rdData is an char *
...
}
}
Basically, in this function it will copy data to rdData and do some verifications.
When I run the code, an error appears when I call this function:
candidate function not viable: no known conversion from 'std::string' (aka 'basic_string') to 'char *' for 1st argument
When I run the code, an error appears when I call this function:
candidate function not viable: no known conversion from 'std::string' (aka 'basic_string') to 'char *' for 1st argument
You did not show the actual code that is trying to pass the std::string to the receiver() function, but the error message is very clear. You simply cannot assign a std::string directly to a non-const char*, which is exactly what the compiler is complaining about.
However, you can get a const char* from a std::string using its c_str() method, and then you can const_cast that to a char* (as long as the function does not try to modify the char data), eg:
std::string result = ...;
receiver(const_cast<char*>(result.c_str()), static_cast<int>(result.size()));
Or, you can simply use &result[0] instead (which is guaranteed in C++11 and later to be contiguous and null-terminated), or you can use result.data() in C++17 and later, eg:
std::string result = ...;
receiver(&result[0]/*result.data()*/, static_cast<int>(result.size()));
Or, you could simply change result from std::string to AnsiString, as its c_str() method returns a non-const char*, eg:
AnsiString result = AnsiString::StringOfChar('0', 8) + myDataModule->getId();
receiver(result.c_str(), result.Length());
Either way, if receiver() only needs to read from data and not modify its content, then it should be changed to take data as a const char* instead (especially since that is what strcpy() expects anyway), eg:
void receiver(const char * data, int num)
Then you can use result.c_str() as-is, no trickery, whether result is an AnsiString or a std::string.

Invalid conversion from 'const char**' to 'char* const*'

I'm doing a school assignment where I have to call execvp, whose method signature is the following
execvp(const char* file, char* const argv[])
However my data is in the form:
std::vector<std::string*>
I've been trying to convert said vector into the right format for the second format of execvp(), but inevitably get the following error:
command.cc:120:29: error: invalid conversion from ‘const char**’ to ‘char* const*’ [-fpermissive]
execvp(args[0], argv);
I've tried different variations but they all lead to this error. This error confuses me, since I have no idea what it means by const*. How can you have a const*? I'd consider changing the std::vector to some other type, but this is an assignment and I'm not really allowed to change it. Below is the code I use to try and create a char*[] from the vector:
const size_t numArgs = _simpleCommands[i]->_arguments.size();
std::vector<const char*> args;
for(size_t j = 0; j < numArgs; ++j)
{
args.push_back(strPtrToCharPtr(_simpleCommands[i]->_arguments[i]));
}
const char** argv = new const char*[numArgs];
for(size_t j = 0; j < numArgs; ++j)
{
argv[j] = args[j];
}
execvp(args[0], argv);
The char* const argv[] prototype means that argv is (the address of) an array of pointers to char, that the pointers in the array cannot be modified, but that the strings they point to can be. This is different from a char const **, which is a pointer to a pointer to char whose characters cannot be modified. Since passing it to a function that might modify the strings in the array would violate the const qualifier of const char **, it is not allowed. (You could do it with const_cast, but that would be solving the wrong problem.)
Since execvp() is a very old UNIX function and would not have the same interface today, it doesn’t have any parameter to tell the OS how many arguments there are, nor does it promise not to modify the contents of the strings in the array. You terminate the array by setting the final element to NULL.
It’s a similar format to the argv parameter of main(). In fact, it becomes the argv parameter of the main() function of the program you run, if it was written in C.
This isn’t a complete solution, since this is a homework assignment and you want to solve it on your own, but you have to create that array yourself. You can do this by creating a std::vector<char *> argv( args.size() + 1 ), setting each element but the last to the .data() pointer from the corresponding element of args, and setting the last element to NULL. Then, pass argv.data() to execvp().
Note that the POSIX.1-2008 standard says,
The argv[] and envp[] arrays of pointers and the strings to which those arrays point shall not be modified by a call to one of the exec functions, except as a consequence of replacing the process image.
Therefore, you ought to be able to get away with casting away the const-ness of the strings in the array, this once, if you don’t mind living dangerously. Normally, you would need to make a modifiable copy of each constant string in the array.
Update
Enough time has passed that I’m not giving out answers to homework. A commenter claimed that my answer did not work on g++8, which means that they didn’t implement the same algorithm I was thinking of. Therefore, posting the complete solution will be helpful.
This actually solves the closely-related problem of how to convert a std::vector<std::string> for use with execvp(). (A std::vector<std::string*> is basically never correct, and certainly not here. If you really, truly want one, change the type of s in the for loop and dereference.)
#define _XOPEN_SOURCE 700
// The next three lines are defensive coding:
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_VERSION 700
#define _XOPEN_UNIX 1
#include <errno.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <vector>
int main()
{
const std::vector<std::string> cmdline{ "ls", "-al" };
std::vector<const char*> argv;
for ( const auto& s : cmdline ) {
argv.push_back( s.data() );
}
argv.push_back(NULL);
argv.shrink_to_fit();
errno = 0;
/* Casting away the const qualifier on the argument list to execvp() is safe
* because POSIX specifies: "The argv[] [...] arrays of pointers and the
* strings to which those arrays point shall not be modified by a call to
* one of the exec functions[.]"
*/
execvp( "/bin/ls", const_cast<char* const *>(argv.data()) );
// If this line is reached, execvp() failed.
perror("Error executing /bin/ls");
return EXIT_FAILURE;
}
Another twist on this would be to write a conversion function that returns the std::vector<const char*> containing the command-line arguments. This is equally efficient, thanks to guaranteed copy elision. I normally like to code using RIIA and static single assignments, so I find it more elegant to return an object whose lifetime is managed automatically. In this case, the elements of argv are weak references to the strings in cmdline, so cmdline must outlive argv. Because we used C-style pointers as weak references, RIIA does not quite work here and we still need to pay attention to object lifetimes.
#define _XOPEN_SOURCE 700
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_VERSION 700
#define _XOPEN_UNIX 1
#include <errno.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <vector>
std::vector<const char*> make_argv( std::vector<std::string>const& in )
{
std::vector<const char*> out;
out.reserve( in.size() + 1 );
for ( const auto& s : in ) {
out.push_back( s.data() );
}
out.push_back(NULL);
out.shrink_to_fit();
return out; // Benefits from guaranteed copy elision.
}
int main()
{
const std::vector<std::string> cmdline{ "ls", "-al" };
errno = 0;
/* Casting away the const qualifier on the argument list to execvp() is safe
* because POSIX specifies: "The argv[] [...] arrays of pointers and the
* strings to which those arrays point shall not be modified by a call to
* one of the exec functions[.]"
*/
execvp( "/bin/ls", const_cast<char* const *>(make_argv(cmdline).data()) );
// If this line is reached, execvp() failed.
perror("Error executing /bin/ls");
return EXIT_FAILURE;
}
I don't understand the std::vector<std::string *> part (are you sure you don't need a std::vector<std::string>?), anyway...
Rule for const: it's applied to the element on the left; if there is non element on the left, it's applied to the element on the right.
So a const char** (or char const **, if you prefer) is a pointer to a pointer to a constant char. I mean: the constant part is the char pointed, not the pointers.
And char * const * is a pointer to a constant pointer to a char; in this case the constant part is one of the two pointers, not the char pointed.
In your case the function
execvp(const char* file, char* const argv[])
expect, as second parameter, a char * const argv[] (a C-style array of constant pointers to a char) that you can see as a char * const *.
But you call
execvp(args[0], argv);
where argv is a char const **, that is different to a char * const *.
So the error: the function expect to be able to modify the pointed char's and you pass a pointer to a pointer to not modifiable char's
And you can't define argv as a char * const *
char * cont * argv = new char * const [numArgs]; // <-- WRONG
because you can't modify it.
So, to solve the problem, I suppose you can define argv as a char **
char** argv = new char* [numArgs];
for(size_t j = 0; j < numArgs; ++j)
argv[j] = args[j];
execvp(args[0], argv);
There ins't problem if you pass a not-constant object to a function that require a constant one (the contrary can be a problem), so you can pass a char ** to a function that expect a char * const *.
1) You don't need to have const * (const pointer) because pointer is automatically converted to const pointer if needed;
2) But you do need to supply char* (not const char* !) array as a second argument of execvp, i.e. your string characters should be modifiable. By having such a signature, execvp reserve its right to modify the supplied argument strings (yes it seems strange - but a process does have right to change its argument - note that main() routine may have (non-const) char** argv arguments!). Thus, you need to get rid of const char* in your piece of code and replace them by char *

cannot convert 'const char **' to 'const char*'

Good morning everyone! I am trying to create a fork/exec call from a parent program via a passed '-e' parameter (e.g. parent -e child key1=val1 ...). As a result I want to copy all the values after the first two in the argv array into a new array child_argv. Something like:
const char *child_argv[10]; // this is actually a global variable
static const char *sExecute;
int I = 0;
const char *Value = argv[1];
sExecute = Value;
for (i=2; i<argc; i++) {
child_argv[I] = argv[i];
I++;
}
child_argv[I] = NULL; // terminate the last array index with NULL
This way I can call the exec side via something like:
execl(sExecute, child_argv);
However I get the error message "error: cannot convert 'const char**' to 'const char*' for argument '2' to 'execl(const char*, const char*, ...)'". I have even tried to use an intermediate step:
const char *child_argv[10]; // this is actually a global variable
static const char *sExecute;
int I = 0;
const char *Value = argv[1];
sExecute = Value;
for (i=2; i<argc; i++) {
const char *Value = argv[i+1];
child_argv[I] = Value;
I++;
}
child_argv[I] = NULL; // terminate the last array index with NULL
But I can't figure this out. Any help would be greatly appreciated!
UPDATE
As was pointed out, I should be using 'execv' instead of 'execl' in this situation. Still getting errors though...
UPDATE 2
I ended up copying the array without the desired parameters of argv. See the post here to see the result How to copy portions of an array into another array
From here: http://linux.die.net/man/3/exec
I think you mean to call "execv" not "execl". Execl seems to take a variable number of arguments, expecting each const char * to be another argument, while execv takes an array of arguments.
You should be using execv. When you convert to execv, for some reason execv expects a array of non-const pointers instead of const pointers, so you either have to just cast the array to (char**) or copy the strings into (char*) pointers.

Initialize char**

I'm very new to C++. I'm trying to call a function that takes in char**:
bool func(char** a) {
//blablabla
}
So it takes in an array of c-strings. I need to create a char**, but nothing works.
char** a = char[255][255]; // error: type name is not allowed
char** a = new char[255][255]; // error: a value of type "char (*)[255]" cannot be used to initialize an entity of type "char **"
char a[][] = {"banana", "apple"};
char** b = &a; // error: a value of type "<error-type> (*)[2]" cannot be used to initialize an entity of type "char **"
At the end I need to do:
char* a[] = {"banana", "apple"};
Why the first few didn't work and why the last one worked?
Thanks in advance.
There's a lot wrong in your code.
char** a = char[255][255]; // error: type name is not allowed
First of all this is not even valid C++ (or C for that matter). Maybe you meant:
char a[255][255];
In any case always remember that the type of a bi-dimensional dynamically allocated array is not ** but (*)[N] which is very different.
char** a = new char[255][255]; // error: a value of type "char (*)[255]" cannot be used to initialize an entity of type "char **"
The error message you provide in the comment explains exactly what I said earlier.
char a[][] = {"banana", "apple"};
In the above code the correct type of the variable a should be char* a[]. Again, arrays and pointer (for what the type is concerned) are very different things. A char array may decay to pointer (if NULL terminated), but for the rest, except with explicit casts, you can't use pointers and arrays like you are doing.
The last one worked because, like I said earlier, char* [] is the correct type for an array of C-strings.
Anyway, if you just doing homework, it is ok to learn this things. But in future development using C++: try not to use "features" that start with C-, like C-strings, C-arrays, etc. C++'s standard library gives you std::string, std::array, std::vector and such for free.
If you really need to allocate dynamic memory (with new and delete, or new[] and delete[]) please use smart pointers, like std::shared_ptr or std::unique_ptr.
You say you are working in C++. Then you can easily ignore const char* and char** and focus about what you can use:
#include <string>
#include <vector>
std::vector<std::string> arrayOfStrings;
arrayOfStrings.push_back("foo");
bool func(const std::vector<std::string>>& a) {
..
}
If you know the size at compile time you can even use std::array:
std::array<255, std::string> fixedArrayOfStrings
EDIT: since you need to build an array of C strings in any case you can easily do it starting from the vector:
const char **arrayOfCstrings = new const char*[vector.size()];
for (int i = 0; i < vector.size(); ++i)
arrayOfCstrings[i] = vector[i].c_str();
func(arrayOfCstrings);
delete [] arrayOfCstrings;
char**
is ambiguous - it can mean:
pointer to pointer
array of c-strings - experienced programmer would write char* arr[] instead
In the first case it is quite simple:
char* niceString = GetNiceString();
func(&niceString);
however in the second case it is slightly more complex. The function will not know the length of the array so you need to end it explicitly with a NULL, just like for example environ is:
char* a[3] = { "One", "Two", NULL }; /* note that this is possibly dangerous
because you assign const char* (READ-ONLY) to char* (WRITABLE) */
func(a); // char*[] gets downgraded to char** implicitly
so char** a = char[255][255]; it's weird to C and C++
and if you want a static 2d array just
char a[255][255];
char ** is a scalar type, you have to cast to (char *[]), try this :
char **temp = (char *[]){"abc", "def","fg"};

How to pass a vector of strings to execv

I have found that the easiest way to build my program argument list is as a vector of strings. However, execv expects an array of chars for the second argument. What's the easiest way to get it to accept of vector of strings?
execv() accepts only an array of string pointers. There is no way to get it to accept anything else. It is a standard interface, callable from every hosted language, not just C++.
I have tested compiling this:
std::vector<string> vector;
const char *programname = "abc";
const char **argv = new const char* [vector.size()+2]; // extra room for program name and sentinel
argv [0] = programname; // by convention, argv[0] is program name
for (int j = 0; j < vector.size()+1; ++j) // copy args
argv [j+1] = vector[j] .c_str();
argv [vector.size()+1] = NULL; // end of arguments sentinel is NULL
execv (programname, (char **)argv);
The prototype for execv is:
int execv(const char *path, char *const argv[]);
That means the argument list is an array of pointers to null-terminated c strings.
You have vector<string>. Find out the size of that vector and make an array of pointers to char. Then loop through the vector and for each string in the vector set the corresponding element of the array to point to it.
I stumbled over the same problem a while ago.
I ended up building the argument list in a std::basic_string<char const*>. Then I called the c_str() method and did a const_cast<char* const*> on the result to obtain the list in a format that execv accepts.
For composed arguments, I newed strings (ordinary strings made of ordinary chars ;) ), took their c_str() and let them leak.
The const_cast is necessary to remove an additional const as the c_str() method of the given string type returns a char const* const* iirc. Typing this, I think I could have used std::basic_string<char*> but I guess I had a reason...
I am well aware that the const-casting and memory leaking looks a bit rude and is indeed bad practise, but since execv replaces the whole process it won't matter anyway.
Yes, it can be done pretty cleanly by taking advantage of the internal array that vectors use. Best to not use C++ strings in the vector, and const_cast string literals and string.c_str()'s to char*.
This will work, since the standard guarantees its elements are stored contiguously (see https://stackoverflow.com/a/2923290/383983)
#include <unistd.h>
#include <vector>
using std::vector;
int main() {
vector<const char*> command;
// do a push_back for the command, then each of the arguments
command.push_back("echo");
command.push_back("testing");
command.push_back("1");
command.push_back("2");
command.push_back("3");
// push NULL to the end of the vector (execvp expects NULL as last element)
command.push_back(NULL);
// pass the vector's internal array to execvp
execvp(command[0], const_cast<char* const*>(command.data()));
return 1;
}
Code adapted from: How to pass a vector to execvp
Do a const_cast to avoid the "deprecated conversion from string constant to 'char*'". String literals are implemented as const char* in C++. const_cast is the safest form of cast here, as it only removes the const and does not do any other funny business. execvp() will not edit the values anyway.
If you want to avoid all casts, you have to complicate this code by copying all the values to char* types not really worth it.
Although if the number of arguments you want to pass to execv/execl is known, it's easier to write this in C.
You can't change the how execv works (not easily anyway), but you could overload the function name with one that works the way you want it to:
int execv(const string& path, const vector<string>& argv) {
vector<const char*> av;
for (const string& a : argv) {
av.push_back(a.c_str());
av.push_back(0);
return execv(path.c_str(), &av[0]);
}
Of course, this may cause some confusion. You would be better off giving it a name other than execv().
NB: I just typed this in off the top of my head. It may not work. It may not even compile ;-)