www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - dynamic array of strings

reply Michael P. <baseball.mjp gmail.com> writes:
import std.stdio;
import std.cstream;
void main()
{
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {
      //what goes here to dynamically allocate memory for the 
     //names array? new statement? .length?
    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
}
How would I go about dynamically allocating memory for the names array in the
part that I commented? 
I'm not really sure about the dynamic array details in D, this is just an
example to help.
-Michael P.
Dec 29 2008
next sibling parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Mon, Dec 29, 2008 at 10:36 PM, Michael P. <baseball.mjp gmail.com> wrote:
 import std.stdio;
 import std.cstream;
 void main()
 {
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {

    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
 }

~= performs an append. It adds the given item to the end of the array.
Dec 29 2008
parent reply Michael P. <baseball.mjp gmail.com> writes:
Jarrett Billingsley Wrote:

 On Mon, Dec 29, 2008 at 10:36 PM, Michael P. <baseball.mjp gmail.com> wrote:
 import std.stdio;
 import std.cstream;
 void main()
 {
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {

    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
 }

~= performs an append. It adds the given item to the end of the array.

Under 1.036, this does not work. Input: michael is cool stop The output is: stopeal st stop What seems to be happening is that the letters of stop are added to the word, and if the word is longer than stop, then the rest of the letters of the word are added. So, I'm not sure if this is a bug or what... -Michael P.
Dec 30 2008
next sibling parent reply Michael P. <baseball.mjp gmail.com> writes:
Denis Koroskin Wrote:

 On Tue, 30 Dec 2008 18:56:08 +0300, Michael P. <baseball.mjp gmail.com> wrote:
 
 Jarrett Billingsley Wrote:

 On Mon, Dec 29, 2008 at 10:36 PM, Michael P. <baseball.mjp gmail.com>  
 wrote:
 import std.stdio;
 import std.cstream;
 void main()
 {
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {

    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
 }

~= performs an append. It adds the given item to the end of the array.

Under 1.036, this does not work. Input: michael is cool stop The output is: stopeal st stop What seems to be happening is that the letters of stop are added to the word, and if the word is longer than stop, then the rest of the letters of the word are added. So, I'm not sure if this is a bug or what... -Michael P.

Now, it's not. What you do is overwrite the string again and again. Try putting "currentName = null;" before doing din.readf().

Thanks, that worked. -Michael P.
Dec 30 2008
parent reply Michael P. <baseball.mjp gmail.com> writes:
Denis Koroskin Wrote:

 On Tue, 30 Dec 2008 20:23:07 +0300, Michael P. <baseball.mjp gmail.com> wrote:
 
 Denis Koroskin Wrote:

 On Tue, 30 Dec 2008 18:56:08 +0300, Michael P. <baseball.mjp gmail.com>  
 wrote:

 Jarrett Billingsley Wrote:

 On Mon, Dec 29, 2008 at 10:36 PM, Michael P. <baseball.mjp gmail.com>
 wrote:
 import std.stdio;
 import std.cstream;
 void main()
 {
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {

    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
 }

~= performs an append. It adds the given item to the end of the


 Under 1.036, this does not work.

 Input:
 michael
 is
 cool
 stop

 The output is:
 stopeal
 st
 stop

 What seems to be happening is that the letters of stop are added to  

 word, and if the word is longer than stop, then the rest of the  

 of the word are added.
 So, I'm not sure if this is a bug or what...
 -Michael P.

Now, it's not. What you do is overwrite the string again and again. Try putting "currentName = null;" before doing din.readf().

Thanks, that worked. -Michael P.

Did you understand the difference? Can you explain the behavior (to yourself)?

Not really... I really have no idea why it wouldn't work before.
Dec 30 2008
parent Michael P. <baseball.mjp gmail.com> writes:
Well, let's go through the code.
 
 First of all, you should undestand that an array is nothing but a pair of
pointer to first element and its length.
 
 Since char[] == string in D1, let's use string instead to make code slightly
more readable.
 
 string[] names; // array of strings that will store our names
 string currentName;
 ...
 din.readf( "%s", &currentName ); // what does this line do?
 
 din.readf tries to minimize allocations by accepting a buffer where the string
will be stored. Buffer will be allocated on heap if provided one is too small
to fit the whole string.
 
 Initially, currentName is null, i.e. currentName.ptr is null and
currentName.length == 0. If you type anything, the data won't fit into buffer
and therefore a new one is created by readf. When you return from readf,
currentName will point to "michael" and have length == 7.
 
 When you call din.readf for second time, you pass your currentName as a buffer
once again. This time it is large enough to fit "is" and therefore it is not
reallocated. "is" is written on top of "michael" and becomes "ischael".
currentName's length is updated to 2. Etc.
 
 Here is names' contents step by step:
 
 At Startup:
 string[] names = []; // empty
 
 Step 1:
 string[] names = [ "michael" ];
 
 Step 2:
 string[] names = [ "ischael", "is" ];
 
 Step 3:
 string[] names = [ "coolael", "co", "cool" ];
 
 Step 4:
 string[] names = [ "stopael", "st", "stop", "stop" ];
 
 When you reset buffer (by doing "currentName = null;"), a new one is allocated
each step and each string gets its own memory. That's it.

So, the strings that are in the array(names) are pointers to the same buffer? And if you set it to null each time, then a new buffer for each string is created instead of being overwritten? Makes sense now, thanks. -Micheal P.
Dec 30 2008
prev sibling parent Gide Nwawudu <gide btinternet.com> writes:
On Tue, 30 Dec 2008 10:56:08 -0500, Michael P.
<baseball.mjp gmail.com> wrote:

Jarrett Billingsley Wrote:

 On Mon, Dec 29, 2008 at 10:36 PM, Michael P. <baseball.mjp gmail.com> wrote:
 import std.stdio;
 import std.cstream;
 void main()
 {
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {

    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
 }

~= performs an append. It adds the given item to the end of the array.

Under 1.036, this does not work. Input: michael is cool stop The output is: stopeal st stop What seems to be happening is that the letters of stop are added to the word, and if the word is longer than stop, then the rest of the letters of the word are added. So, I'm not sure if this is a bug or what... -Michael P.

currentName is used as a buffer that is overwritten on each call to din.readf. It is easier to explicitly duplicate the contents to create a copy that is stored in the array names.
 names ~= currentName;


Gide
Jan 01 2009
prev sibling next sibling parent reply "Tim M" <a b.com> writes:
On Tue, 30 Dec 2008 16:36:24 +1300, Michael P. <baseball.mjp gmail.com>  
wrote:

 import std.stdio;
 import std.cstream;
 void main()
 {
   char[][] names;
   char[] currentName;
   while( true )
   {
     din.readf( "%s", &currentName );
     if( currentName == "stop" )
     {
       break;
     }
     else
     {
       //what goes here to dynamically allocate memory for the
      //names array? new statement? .length?
     }
   }
   foreach( name; names )
   {
     writefln( name );
   }
 }
 How would I go about dynamically allocating memory for the names array  
 in the part that I commented?
 I'm not really sure about the dynamic array details in D, this is just  
 an example to help.
 -Michael P.

Where is din.readf? If it is a c function then it won't be able to set up the dynamic array. You can set the length property to allocte the memory and pass the c function currentName.ptr. To append currentName to names do somehing like: names ~= currentName;
Dec 29 2008
next sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Mon, Dec 29, 2008 at 10:53 PM, Tim M <a b.com> wrote:
 Where is din.readf? If it is a c function then it won't be able to set up
 the dynamic array.

In std.cstream, din is an instance of std.stream.Stream bound to standard in.
Dec 29 2008
prev sibling parent "Tim M" <a b.com> writes:
On Tue, 30 Dec 2008 17:00:10 +1300, Jarrett Billingsley  
<jarrett.billingsley gmail.com> wrote:

 On Mon, Dec 29, 2008 at 10:53 PM, Tim M <a b.com> wrote:
 Where is din.readf? If it is a c function then it won't be able to set  
 up
 the dynamic array.

In std.cstream, din is an instance of std.stream.Stream bound to standard in.

Thanks for that. As you can see I use tango.
Dec 29 2008
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 30 Dec 2008 18:56:08 +0300, Michael P. <baseball.mjp gmail.com> wrote:

 Jarrett Billingsley Wrote:

 On Mon, Dec 29, 2008 at 10:36 PM, Michael P. <baseball.mjp gmail.com>  
 wrote:
 import std.stdio;
 import std.cstream;
 void main()
 {
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {

    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
 }

~= performs an append. It adds the given item to the end of the array.

Under 1.036, this does not work. Input: michael is cool stop The output is: stopeal st stop What seems to be happening is that the letters of stop are added to the word, and if the word is longer than stop, then the rest of the letters of the word are added. So, I'm not sure if this is a bug or what... -Michael P.

Now, it's not. What you do is overwrite the string again and again. Try putting "currentName = null;" before doing din.readf().
Dec 30 2008
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 30 Dec 2008 20:23:07 +0300, Michael P. <baseball.mjp gmail.com> wrote:

 Denis Koroskin Wrote:

 On Tue, 30 Dec 2008 18:56:08 +0300, Michael P. <baseball.mjp gmail.com>  
 wrote:

 Jarrett Billingsley Wrote:

 On Mon, Dec 29, 2008 at 10:36 PM, Michael P. <baseball.mjp gmail.com>
 wrote:
 import std.stdio;
 import std.cstream;
 void main()
 {
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {

    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
 }

~= performs an append. It adds the given item to the end of the


 Under 1.036, this does not work.

 Input:
 michael
 is
 cool
 stop

 The output is:
 stopeal
 st
 stop

 What seems to be happening is that the letters of stop are added to  

 word, and if the word is longer than stop, then the rest of the  

 of the word are added.
 So, I'm not sure if this is a bug or what...
 -Michael P.

Now, it's not. What you do is overwrite the string again and again. Try putting "currentName = null;" before doing din.readf().

Thanks, that worked. -Michael P.

Did you understand the difference? Can you explain the behavior (to yourself)?
Dec 30 2008
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 30 Dec 2008 20:34:00 +0300, Michael P. <baseball.mjp gmail.com> wrote:

 Denis Koroskin Wrote:

 On Tue, 30 Dec 2008 20:23:07 +0300, Michael P. <baseball.mjp gmail.com>  
 wrote:

 Denis Koroskin Wrote:

 On Tue, 30 Dec 2008 18:56:08 +0300, Michael P.  


 wrote:

 Jarrett Billingsley Wrote:

 On Mon, Dec 29, 2008 at 10:36 PM, Michael P.  




 wrote:
 import std.stdio;
 import std.cstream;
 void main()
 {
  char[][] names;
  char[] currentName;
  while( true )
  {
    din.readf( "%s", &currentName );
    if( currentName == "stop" )
    {
      break;
    }
    else
    {

    }
  }
  foreach( name; names )
  {
    writefln( name );
  }
 }

~= performs an append. It adds the given item to the end of the


 Under 1.036, this does not work.

 Input:
 michael
 is
 cool
 stop

 The output is:
 stopeal
 st
 stop

 What seems to be happening is that the letters of stop are added to

 word, and if the word is longer than stop, then the rest of the

 of the word are added.
 So, I'm not sure if this is a bug or what...
 -Michael P.

Now, it's not. What you do is overwrite the string again and again. Try putting "currentName = null;" before doing din.readf().

Thanks, that worked. -Michael P.

Did you understand the difference? Can you explain the behavior (to yourself)?

Not really... I really have no idea why it wouldn't work before.

Well, let's go through the code. First of all, you should undestand that an array is nothing but a pair of pointer to first element and its length. Since char[] == string in D1, let's use string instead to make code slightly more readable. string[] names; // array of strings that will store our names string currentName; ... din.readf( "%s", &currentName ); // what does this line do? din.readf tries to minimize allocations by accepting a buffer where the string will be stored. Buffer will be allocated on heap if provided one is too small to fit the whole string. Initially, currentName is null, i.e. currentName.ptr is null and currentName.length == 0. If you type anything, the data won't fit into buffer and therefore a new one is created by readf. When you return from readf, currentName will point to "michael" and have length == 7. When you call din.readf for second time, you pass your currentName as a buffer once again. This time it is large enough to fit "is" and therefore it is not reallocated. "is" is written on top of "michael" and becomes "ischael". currentName's length is updated to 2. Etc. Here is names' contents step by step: At Startup: string[] names = []; // empty Step 1: string[] names = [ "michael" ]; Step 2: string[] names = [ "ischael", "is" ]; Step 3: string[] names = [ "coolael", "co", "cool" ]; Step 4: string[] names = [ "stopael", "st", "stop", "stop" ]; When you reset buffer (by doing "currentName = null;"), a new one is allocated each step and each string gets its own memory. That's it.
Dec 30 2008