Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert char[][] to char**

I have a char[][]

  char c[2][2]={
    {'a','b'},
    {'c','d'}
  };

How can I convert it to char**?

The objective here is to use the converted char** as an input for a main function, which only accepts char** as its input. Both C/C++ solutions are acceptable.

like image 976
zell Avatar asked May 18 '15 22:05

zell


4 Answers

While you could easily switch from char[] to char*, the same is not possible with char[][] and char**:

  • your char[2][2] is a 2 dimensional array having all the elements stored contiguously. To access one element, the compiler computes the offset knowing the size of each row.
  • char** points to an array that contains pointers to char. To access one element, your compiler computes the offset of the pointer in the left-most, load that poitner, then access to the element.

Workaround:

char *pc[2]={c[0],c[1]}; 
cout << pc[1][1]<<endl;   // prints out the same as c[1][1]
// you can pass `pc` when a `char**` is needed

Remark: this compiles perfectly. However, some functions with an argument like char **av expect in reality av[i] to be a null terminated c-string. In this case, although your code would compile, the results might not be what you expect (buffer overflow).

like image 78
Christophe Avatar answered Sep 29 '22 03:09

Christophe


You cannot convert a char[2][2] to char**, you can only convert it to char(*)[2],

char (*p)[2] = c;

The above is a pointer to array-of-2-char. Note that you need this 2 and cannot just write char** p, since in the latter case you are not able to perform pointer arithmetic (the pointer won't know how many elements to "jump" when incrementing, and you won't be able to address the elements of your array (in this case the rows)).

like image 45
vsoftco Avatar answered Sep 29 '22 02:09

vsoftco


You could pass the array into the function like this:

char c[2][2] = {
    {'a','b'},
    {'c','d'}
};

char* x[] { c[0], c[1] };
func(x); // Assuming something like: void func(char** p);
like image 23
Beta Carotin Avatar answered Sep 29 '22 02:09

Beta Carotin


NOTE: Although this answer may explain/illustrate the problem quite well other answers are preferable that recommend creating an automatic variable char*[2]; rather than allocating with new as this answer does.

Original answer:

The problem is char c[2][2] is a contiguous block of char. The compiler allocates only 4 char objects.

When you build an array of arrays (char** c) you need to manually allocate an array of pointers to char and then allocate (or assign) and array of char to each of those pointers.

So to convert your array char c[2][2] to an array of arrays you have to first create the array of pointers and then assign the array of the first element of each array of char to that.

Something like this:

void func(char** c)
{
    for(int x = 0; x < 2; ++x)
        for(int y = 0; y < 2; ++y)
            std::cout << c[x][y] << ' ';
    std::cout << '\n';
}

int main(int, char* argv[])
{
    // one contiguous block of 4 chars
    char c[2][2]={
        {'a','b'},
        {'c','d'}
      };

    char** param = new char*[2]; // create your own pointer array
    param[0] = &c[0][0]; // assign the first element of each char array
    param[1] = &c[1][0];

    func(param); // call your func

    delete[] param; // cleanup
}

If you have C++11 you can use a smart pointer to prevent memory leaks if an exception is thrown or someone forgets to delete.

int main(int, char* argv[])
{
    // one contiguous block of 4 chars
    char c[2][2]={
        {'a','b'},
        {'c','d'}
      };

    // use a smart pointer
    std::unique_ptr<char*[]> param(new char*[2]);
    param[0] = &c[0][0];
    param[1] = &c[1][0];

    func(param.get()); // now if this throws, no memory leak

    // delete[] param; // NO NEED TO DELETE
}
like image 37
Galik Avatar answered Sep 29 '22 03:09

Galik