Question

Recently, I am trying to make good practice on C now I come to a command execution. It tells me that I should us char**? But am I have some concept wrong.

Please help me. Code is here

int excution(int cnt, char token[][BUFSIZE],int *t_token)
{
    setenv ("PATH", "/bin:/bin/usr:", 1);
    //printf("%s",getenv("PATH")); // check environement
    const char *b_cd="cd";
    const char *b_exit="exit";
    const char *b_fg="fg";
    const char *b_jobs="jobs";
    int  i,j,k;
    //STEP 9:excute normal commanand
    char args[cnt][BUFSIZE];
    for(i=0;i<MAXARG;i++)
    {
        if(t_token[i]==COMMAND)
        {
            strcpy(args[0],token[i]); // copy 1st ARG
            j=1;
            while(t_token[i+1]==ARG)  
            {
                strcpy(args[j],token[i+1]);
                i++;
                j++;
            }
            for(k=0;k<j;k++)
            {
            printf("%s\n", args[k]);
            }
            execvp (args[0], args);
        }
    }

It gives me warning in compilation. But it gives segmentation fault if I change 2D array to a char**....

warning: passing argument 2 of ‘execvp’ from incompatible pointer type [enabled by default] /usr/include/unistd.h:579:12: note: expected ‘char * const*’ but argument is of type ‘char (*)[256]’

Was it helpful?

Solution

Maybe I'm just old, but when I see char var[X][Y] I think the compiler is going to allocate a chunk of memory of sizeof(char)*X*Y and then var[i] will be equal to var+(i*Y*(sizeof(char))). As long as everybody knows what X & Y are, all is cool. But execvp() doesn't know your X & Y sizes.

In contrast, char * var[X] will give me an array of X pointers each sizeof(char*), or a blob of memory of sizeof(char*)*X.

Now char's are generally 1 byte. char* is generally 4 or 8 bytes, but can vary depending on your system.

So char * var[X] might be a chunk of memory X*8 bytes in size, and anyone receiving var as an argument would know how to access each char* pointer in that array as pointer sizes are well known by the compiler and it's just a standard offset.

On the other hand, anyone receiving char var[X][Y] is going to be really confused. There's no way to tell where one argument ends and another begins in that giant chunk of memory.

Long story short: Use char * args[SIZE];, use arg[i] = "command" or arg[i] = token[j], and learn about pointers.

p.s. char** is a pointer to a pointer to char. (It's, say, 8 bytes that points to another memory address of 8 bytes of data that contains the memory address of a char (1-byte) value. This makes more sense when we talk about storing strings as null-terminated (char(0)) arrays of characters - e.g. sequentially stored characters, so if we know the address of the first character in the string we can just increment the pointer to get the next character until we hit zero, the null character '\0'.)

It's similar to, but not quite the same as an array of pointers to char. (Which is, say, 8 bytes that points to a memory address containing at least 8 bytes of data, perhaps N*8 bytes of sequential memory addresses (pointers). Again, just like with the sequential char array, we can have an array of char*, one stored after the other in memory.)

It would be more accurate to say a char** is roughly equal to a char*[N], only the char** doesn't allocate any memory for the internal char* pointers whereas char*[N] does - it allocate space for N char* pointers.

When receiving an array of pointers to char (char*[]), you can declare it as a pointer to a pointer to char (char**) and still iterate through the array. You just need to have the right underlying block of memory (data) located (passed in) where that pointer points to.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top