How to pass a vector to execvp
Not directly; you'd need to represent the vector as a NULL-terminated array of string pointers somehow. If it's a vector of strings, that is straightforward to do; if it's some other kind of data you would have to figure how to encode it as strings.
execvp() using vectorstring *
You will need to create a new array of pointers to the strings' data, instead of to the std::string
s themselves. There are many ways to do this, but one simple way is to use another std::vector
and a structured for loop:
assert(_arguments.size() > 0); // else the executable will be invalid
std::vector<const char *> args;
args.reserve(_arguments.size() + 1);
for(string *sp: _arguments) {
args.push_back(sp->c_str());
}
args.push_back(nullptr); // needed to terminate the args list
execvp(args[0], args.data());
How to pass a vector of strings to execv
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);
Convert vectorstring to char** for use in execvp
I found that the answer lies with adding the NULL terminator to the end of the vector so that execvp knows where to end pvec.data(); This is thanks to Fatih above.
std::vector<char*> pvec(tokens.size());
std::transform(tokens.begin(), tokens.end(), pvec.begin(), [](auto& str) {
return &str[0];
});
pvec.push_back(NULL);
pvec.data();
pid = fork();
// if we enter child process
if (pid == 0)
{
if (execvp(pvec.data()[0], pvec.data()) == -1)
{
printf("right here officer\n");
}
exit(EXIT_FAILURE);
}```
execvp not working when converting from vectorstring to vectorchar* to char**
First, there's no point in copying the std::string
s if the next thing you are going to do is call execvp
.
If the execvp
succeeds, then it will never return and the entire memory image will vanish into smoke (or, more accurately, be replaced by a completely new image). In the course of constructing the new image, exec*
will copy the argv array (and the environment array) into it. In any event, the std::vector
and std::string
destructors will never be invoked.
If, on the other hand, the execvp
fails, then the argument passed into it will not have been modified. (Posix: "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.")
In either case, there was no need to copy the character strings. You can use std::string::c_str()
to extract a pointer to the underlying C string (as a const char*
, but see below).
Second, if you're using C++11 or more recent, std::vector
conveniently comes with a data()
member function which returns a pointer to the underlying storage. So if you have std::vector<char*> svec
, then svec.data()
will be the underlying char*[]
, which is what you want to pass into execvp
.
So the problem reduces to creating a std::vector<char*>
from a std::vector<std::string>
, which is straightforward:
else if (kidpid == 0) {
// I am the child.
std::vector<char*> argc;
// const_cast is needed because execvp prototype wants an
// array of char*, not const char*.
for (auto const& a : args)
argc.emplace_back(const_cast<char*>(a.c_str()));
// NULL terminate
argc.push_back(nullptr);
// The first argument to execvp should be the same as the
// first element in argc, but we'll assume the caller knew
// what they were doing, and that program is a std::string.
execvp(program.c_str(), argc.data());
// It's not clear to me what is returning here, but
// if it is main(), you should return a small positive value
// to indicate an error
return 1;
}
how do i convert std::vector to char ** in a reliable way?
As Pete Becker says, the issue's probably that you haven't called it properly - and specifically that the a
argument doesn't point to a sufficiently large array of char*
s to write to.
Anyway, do you really need to screw around with dynamic memory allocation here? Having std::vector
manage memory for you is much easier, safer, and more concise. Perhaps you can do something like below, then pass the result's .data()
value to execvp
? You do need to make sure the vector of strings passed as an argument is not mutated by the caller after this call and before calling execvp
, otherwise the pointers you collect may be invalidated.
std::vector<const char*> getVectorOfPointersToStrings(std::vector<std::string> const& v) {
std::vector<const char*> result;
for (const auto& s : v)
result.push_back(s.c_str());
result.push_back(nullptr);
return result;
}
Execvp not executing ping command with arguments
vector<char*> pingArgs;
pingArgs.push_back("www.google.com");
pingArgs.push_back(NULL);
The first parameter to a program, it's argv[0]
, is the name of the program itself.
Here, you're merely informing the ping
program that it's name is www.google.com
, and it has no additional parameters.
vector<char*> pingArgs;
pingArgs.push_back("ping");
pingArgs.push_back("www.google.com");
pingArgs.push_back(NULL);
The first parameter to execvp
is the executable to execute, but you still must provide all parameters separately.
However, all of the above is completely wrong anyway, for a tangential reason. In modern C++ string literals are const char *
, and not char *
. You must be using an ancient C++ compiler that either relaxes const
-correctness when it comes to string literals or fails to implement it correctly, and I expect every modern C++ compiler to fail to compile the shown code for this unrelated reason.
Correctly doing this requires a little bit more work, in C++, but that's not directly related to the question you asked, and would be a separate question.
Is it legal to pass a null program argument vector to execve()?
The man page for the execve()
system call says
The
argv
andenvp
arrays must each include a null pointer at the end of the array.
If your program doesn't conform to those requirements, there's no certainty of how well things will go from that point on. If it "works" for some programs, that's just bad luck.
The man page also says
By convention, the first of these strings (i.e.,
argv[0]
) should contain the filename associated with the file being executed.
That convention is rather strong (mandated by POSIX), so programs that fail to do so can be considered buggy. It's probably a good idea for your main()
to test it's been called correctly if you're going to rely on argv[0]
so you can fail with a nice error message rather than a fault, but not all programs do.
Related Topics
How to Print the Address of Char Array
C++11 Cross Compiler/Standard Library Random Distribution Reproducibility
Error: 'Null' Was Not Declared in This Scope
How to Use Shared Library Created in C++ in a C Program
Partially Truncating a Stream (Fstream or Ofstream) in C++
What Is This Crazy C++11 Syntax ==> Struct:Bar {} Foo {};
Cmake with Include and Source Paths - Basic Setup
Calling Constructors in C++ Without New
What Does Iterator->Second Mean
Can You Access Private Member Variables Across Class Instances
What Is the Purpose of Std::Make_Pair VS the Constructor of Std::Pair
How to Resume Input Stream After Stopped by Eof in C++