5

I am having trouble with using execvp(). execvp() expects type char * const* as second parameter. I want to parse arguments passed to application (in argv) and make an array of that type. For example, user is invoking the binary as given below:

./myapp "ls -a -l"

And then I make the below array from it:

{"ls", "-a", "-l", NULL}

Now, my code looks like:

    const char* p[10];
    char temp[255] = "ls -a -l";

    p[0] = strtok(temp, " ");
    for(i=0; i<9; i++) {
        if( p[i] != NULL ) {
            p[i+1] = strtok(NULL, " ");
        } else {
            break;
        }
    }

It works, but I am getting the warning:

main.c:47: warning: passing argument 2 of ‘execvp’ from incompatible pointer type /usr/include/unistd.h:573: note: expected ‘char * const*’ but argument is of type ‘const char **’

How to do it correctly?

marxin
  • 3,692
  • 3
  • 31
  • 44
  • Where in the code are you calling `execvp()` ? What is `test` variable doing in `strtok()` where I guess `temp` variable should be. Where have you defined the `test` variable? – askmish Oct 18 '12 at 18:28
  • Of course test is a temp, i just written it for example. im calling execvp(p[0], p)... problem is in type of p. – marxin Oct 18 '12 at 18:29
  • 1
    BTW: your loop-logic is buggy. If there happen to be 9 or more tokens in the input string, the p[] array will not have a final NULL pointer. – wildplasser Oct 18 '12 at 18:53
  • Ofc i know it. Its just an example. In my code i will use malloc/realloc. – marxin Oct 18 '12 at 18:57

2 Answers2

4

The problem is that the second parameter of execvp is a char * const *, which is a "pointer to a constant pointer to non-constant data". You're trying to pass it a const char **, which is a "pointer to a pointer to constant data".

The way to fix this is to use char ** instead of const char ** (since "pointer to X" is always allowed to be convert to "pointer to const X", for any type X (but only at the top level of pointers):

char* p[10];
p[0] = ...;
// etc.

Note that if you do need to insert const char * parameters, you can cast them char * as long as you don't modify them. Although the arguments to the exec* family of functions are declared as non-const, they won't ever modify them (see the POSIX 2008 specification). The rationale there explains why they are declared as non-const.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • Wow, great answer to an unexpectedly perplexing question. Thanks for the POSIX reference or else this reasonable absurdity would have seemed wholly unreasonable! – bigjosh May 16 '18 at 01:24
4

You can just use char *p[10].

To break it down: char *const *p means "nonconstant pointer to constant pointer of nonconstant char" -- that is, p is writable, p[0] is not writable, and p[0][0] is writable.

nneonneo
  • 171,345
  • 36
  • 312
  • 383
  • Thank you. Do you know if it is safe? – marxin Oct 18 '12 at 18:44
  • 3
    Yes. Per the POSIX 2008 spec, none of the `exec` functions will write to the strings; `char *const*` is used for compatibility (instead of the more correct `const char *const*`). – nneonneo Oct 18 '12 at 18:45