Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a char* const * for execvp()

Tags:

c++

Having a great deal of trouble satisfying the second argument of execvp. The compiler says it needs a char* const* passed where I have a const char**. I would prefer it made from user input:

std::string x;
std::cout<<" [CMD]: ";
getline(std::cin, x);
const char** args = fillArgs(x);
execvp(args[0], args);

The code for fillArgs is to convert the string to a dynamically allocated pointer to an array of chars. In a nutshell it looks like this:

const char** fillArgs(std::string currentCMD)
{
     //Above this, the string passed into the function is split into substrings separated
    //by whitespaces and each is placed into the string vector called input.

    const char** command = new const char*[SIZE];
    for(int i = 0; i < SIZE; i++)
    {
        command[i] = input[i].c_str();
    }
    return command;
}

I am aware it needs to end with a nullpointer and took care of that in the code above. Suggestions?

like image 254
Leif Chipman Avatar asked Sep 01 '25 20:09

Leif Chipman


1 Answers

char* const argv[] (and char* const *argv) is an array of const pointers to mutable char arrays. (Even if execvp probably will not modify the strings).

But const char** args (same as char const** args) is an array of mutable pointers to const char arrays.

std::string::c_str returns a const char* pointer to a const char array. But execvp requires mutable char arrays.


One solution would be to use const_cast:

const char* command = input[i].c_str();
char* command_mutable = const_cast<char*>(command);

char* const *argv;
argv[i] = command_mutable;

This works in the case of execvp because it just reads the strings and copies them for use by the new executable, and does not return. For a function that could modify the strings and return normally, it is undefined behavior.

But another problem is that the pointer returned by c_str is valid only as long as the std::string object exists. The function fillArgs is incorrect because when it returns the pointers in the return value are invalid. (Also the command array itself if it was allocated on the stack.)

So this would work:

std::string str = "example";
char* const args[3];
args[1] = const_cast<char*>(str.c_str());
args[2] = nullptr;
execvp(args[0], args);
// Not the other program is running

When using another function than execvp that could modify the array, it would be better to create a temporary array for the function:

std::string str = "example";
std::unique_ptr<char[]> tmp_str(new char[str.size() + 1]);
std::memcpy(tmp_str.get(), str.c_str(), str.size() + 1);
char* const args[3];
args[1] = tmp_str.get();
args[2] = nullptr;
something(args[0], args);
tmp_str.reset(); // release the temporary memory
like image 110
tmlen Avatar answered Sep 03 '25 16:09

tmlen