View mode: basic / threaded / horizontal-split · Log in · Help
March 23, 2012
string[] to char**
What's the best way to convert char** from string[]?
March 23, 2012
Re: string[] to char**
On Friday, 23 March 2012 at 15:48:12 UTC, simendsjo wrote:
> What's the best way to convert char** from string[]?

This is one way to do it:


import std.algorithm, std.array, std.string, core.stdc.stdio;
void main() {
    auto data = ["red", "yellow", "green"];
    immutable(char)** p = array(map!toStringz(data)).ptr;
    printf("%s %s %s\n", p[0], p[1], p[2]);
}


Note: the pointer array is managed by the D GC.

With DMD 2.059:

immutable(char)** p = data.map!toStringz().array().ptr;

Bye,
bearophile
March 23, 2012
Re: string[] to char**
On 03/23/2012 08:48 AM, simendsjo wrote:
> What's the best way to convert char** from string[]?

In C, char** communicates transfer of ownership. Is that what you are 
trying to do? Are you going to pass a slice to a C function to be filled 
in by that C function?

Such functions usually assign to *str. In that case you can use the 
"make slice from raw pointer" method below. I hope others will answer my 
concern in the comment below:

import std.stdio;
import std.c.stdlib;
import std.c.string;

void C_func_with_an_out_parameter(char ** str)
{
    *str = cast(char*)calloc(1, 10);
    (*str)[0] = 'A';
    (*str)[1] = '\0';
}

void main()
{
    char * p;
    C_func_with_an_out_parameter(&p);

    char[] slice = p[0..strlen(p)];     // <-- make a D slice

    /*
     * Note: I don't think that the memory that
     * std.stdlib.calloc() returns is managed by the GC. For
     * that reason, I don't think it will be safe to share the
     * element with another slice and expect normal behavior
     * of element-sharing between slices.
     *
     * In other words, this would be risky:
     *
     *     char[] anotherSlice = slice;
     */
    writeln(slice);

    free(p);
}

Ali
March 23, 2012
Re: string[] to char**
On 03/23/2012 11:23 AM, Ali Çehreli wrote:
> On 03/23/2012 08:48 AM, simendsjo wrote:
>  > What's the best way to convert char** from string[]?
>
> In C, char** communicates transfer of ownership.

Ok, I once again misunderstood the question. :( My question in the 
comment remains.

Thank you,
Ali
March 23, 2012
Re: string[] to char**
On 3/23/12, bearophile <bearophileHUGS@lycos.com> wrote:
> This is one way to do it:
>      immutable(char)** p = array(map!toStringz(data)).ptr;

This is asked so frequently that I think we could consider adding it to Phobos.
March 24, 2012
Re: string[] to char**
On Fri, 23 Mar 2012 19:23:07 +0100, Ali Çehreli <acehreli@yahoo.com> wrote:

> On 03/23/2012 08:48 AM, simendsjo wrote:
>  > What's the best way to convert char** from string[]?
>
> In C, char** communicates transfer of ownership. Is that what you are  
> trying to do? Are you going to pass a slice to a C function to be filled  
> in by that C function?
>
> Such functions usually assign to *str. In that case you can use the  
> "make slice from raw pointer" method below. I hope others will answer my  
> concern in the comment below:
>
> import std.stdio;
> import std.c.stdlib;
> import std.c.string;
>
> void C_func_with_an_out_parameter(char ** str)
> {
>      *str = cast(char*)calloc(1, 10);
>      (*str)[0] = 'A';
>      (*str)[1] = '\0';
> }
>
> void main()
> {
>      char * p;
>      C_func_with_an_out_parameter(&p);
>
>      char[] slice = p[0..strlen(p)];     // <-- make a D slice
>
>      /*
>       * Note: I don't think that the memory that
>       * std.stdlib.calloc() returns is managed by the GC. For
>       * that reason, I don't think it will be safe to share the
>       * element with another slice and expect normal behavior
>       * of element-sharing between slices.
>       *
>       * In other words, this would be risky:
>       *
>       *     char[] anotherSlice = slice;
>       */
>      writeln(slice);
>
>      free(p);
> }
>
> Ali

I'm not sure of the semantics of the function yet. Don't know if it copies  
the argument or stores it, if it frees it or expects me to free it :|
But it's not filling the array.
March 24, 2012
Re: string[] to char**
On Fri, 23 Mar 2012 17:09:18 +0100, bearophile <bearophileHUGS@lycos.com>  
wrote:

> On Friday, 23 March 2012 at 15:48:12 UTC, simendsjo wrote:
>> What's the best way to convert char** from string[]?
>
> This is one way to do it:
>
>
> import std.algorithm, std.array, std.string, core.stdc.stdio;
> void main() {
>      auto data = ["red", "yellow", "green"];
>      immutable(char)** p = array(map!toStringz(data)).ptr;
>      printf("%s %s %s\n", p[0], p[1], p[2]);
> }
>
>
> Note: the pointer array is managed by the D GC.
>
> With DMD 2.059:
>
> immutable(char)** p = data.map!toStringz().array().ptr;
>
> Bye,
> bearophile

Thanks. A lot shorter and safer than my current approach. I also expect  
toStringz doesn't make a copy if \0 is at the end.

For reference, my current approach was:

auto strings = ["a", "b"];
auto c_strings = cast(char**)malloc((char*).sizeof * strings.length);
for(int i; i < strings.length; i++)
  c_strings[i] = strings[i].ptr;
March 24, 2012
Re: string[] to char**
On Sat, 24 Mar 2012 11:41:48 +0100, simendsjo <simendsjo@gmail.com> wrote:

> On Fri, 23 Mar 2012 17:09:18 +0100, bearophile  
> <bearophileHUGS@lycos.com> wrote:
>
>> On Friday, 23 March 2012 at 15:48:12 UTC, simendsjo wrote:
>>> What's the best way to convert char** from string[]?
>>
>> This is one way to do it:
>>
>>
>> import std.algorithm, std.array, std.string, core.stdc.stdio;
>> void main() {
>>      auto data = ["red", "yellow", "green"];
>>      immutable(char)** p = array(map!toStringz(data)).ptr;
>>      printf("%s %s %s\n", p[0], p[1], p[2]);
>> }
>>
>>
>> Note: the pointer array is managed by the D GC.
>>
>> With DMD 2.059:
>>
>> immutable(char)** p = data.map!toStringz().array().ptr;
>>
>> Bye,
>> bearophile
>
> Thanks. A lot shorter and safer than my current approach. I also expect  
> toStringz doesn't make a copy if \0 is at the end.
>
> For reference, my current approach was:
>
> auto strings = ["a", "b"];
> auto c_strings = cast(char**)malloc((char*).sizeof * strings.length);
> for(int i; i < strings.length; i++)
>    c_strings[i] = strings[i].ptr;

Oh, I didn't find toStringz, so I turned it into:

auto c_strings = strings.map!(toUTFz!(char*)).array().ptr;
March 24, 2012
Re: string[] to char**
On Fri, 23 Mar 2012 22:42:08 +0100, Andrej Mitrovic  
<andrej.mitrovich@gmail.com> wrote:

> On 3/23/12, bearophile <bearophileHUGS@lycos.com> wrote:
>> This is one way to do it:
>>      immutable(char)** p = array(map!toStringz(data)).ptr;
>
> This is asked so frequently that I think we could consider adding it to  
> Phobos.

Yes. The first thing I tried was to!(char**)(strings), but that didn't work
March 24, 2012
Re: string[] to char**
simendsjo:

> Oh, I didn't find toStringz, so I turned it into:

It's in std.string.

> auto c_strings = strings.map!(toUTFz!(char*)).array().ptr;

That's wrong syntax, that 2.059head doesn't enforce yet, map needs an ending ().


Bye,
bearophile
Top | Discussion index | About this forum | D home