Search code examples
d

Trouble with a 3D array of chars in D


I'm learning D, and I have a simple program that reads in a text file line by line, separates each line into its distinct words, and prints the whole thing to stdout.

import std.stdio;
import std.string;

void main(string args[])
{
    char[][][] lines;
    auto input = File(args[1], "r");
    foreach(line; input.byLine())
    {
        auto words = split(strip(line));
        lines ~= words;
    }

    foreach(line; lines)
    {
        writeln(line);
    }
}

The code for creating words works. If I just call writeln on words each time it's assigned, I get the output I want. But if I add words to lines and output lines, then strange things happen. lines has an entry for each line in the source file, but each line is a corrupt version of the last line read. For instance, if the last line of the file looks like this:

END    START        * End of routine

I get output that looks something like this:

[       , END, ST, *, End , f rout, ne,    ,     , e other]
[     , END, ST, *, End of, rout, ne,      ,   , e othe]
[    , END, STAR, *, End of, rout, ne.,        
e]
[    , END, START  , *, End of, rout, ne.,        
e]
[END , STAR]
[     , END, START     , *, End , f , out, ne.  ]
[END, START, *, End, of ro, tine. ,  ,   ,  
]
[END, STA, *, o,  r, ut]
[  , END , S, *, End, o,  r, utine.,  ,   ,  , 
,  o]
[END, START    , *, of routi, e.,   ]

Any idea what I'm doing wrong?


Solution

  • You main problem is that byLine is using the same buffer, you need to duplicate it so it doesn't override your data

    auto words = split(strip(line).dup);
    

    A more appropriate storage class is string instead of char[], unless you intend on modifying the actual characters. However, you will get a compiler error in v 2.0 because line will be char[]. This is just a matter of duplicating it as an immutable string instead.

    auto words = split(strip(line).idup);
    

    This way your program would look like

    import std.stdio;
    import std.string;
    
    void main(string[] args)
    {
        string[][] lines;
        auto input = File(args[1], "r");
        foreach(line; input.byLine())
        {
            auto words = split(strip(line).idup);
            lines ~= words;
        }
    
        foreach(line; lines)
        {
            writeln(line);
        }
    }