www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - string[] to char**

reply simendsjo <simendsjo gmail.com> writes:
What's the best way to convert char** from string[]?
Mar 23 2012
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
Mar 23 2012
parent bearophile <bearophileHUGS lycos.com> writes:
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
Mar 24 2012
prev sibling next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Mar 23 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Mar 23 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
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.
Mar 23 2012
prev sibling next sibling parent simendsjo <simendsjo gmail.com> writes:
On Fri, 23 Mar 2012 19:23:07 +0100, Ali =C3=87ehreli <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 fill=

 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 =

 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 =3D cast(char*)calloc(1, 10);
      (*str)[0] =3D 'A';
      (*str)[1] =3D '\0';
 }

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

      char[] slice =3D 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 =3D slice;
       */
      writeln(slice);

      free(p);
 }

 Ali

I'm not sure of the semantics of the function yet. Don't know if it copi= es = the argument or stores it, if it frees it or expects me to free it :| But it's not filling the array.
Mar 24 2012
prev sibling next sibling parent simendsjo <simendsjo gmail.com> writes:
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;
Mar 24 2012
prev sibling next sibling parent simendsjo <simendsjo gmail.com> writes:
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;
Mar 24 2012
prev sibling parent simendsjo <simendsjo gmail.com> writes:
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
Mar 24 2012