字符串的分配内存

时间:2017-01-20 12:37:51

标签: string d

在D string中是不可变char[]的别名。所以对字符串处理的每个操作都要分配内存。我绑了检查它,但在替换字符串中的符号后,我看到了相同的地址。

string str = "big";
writeln(&str);
str.replace("i","a");
writeln(&str);

输出:

> app.exe
19FE10
19FE10

我尝试使用ptr

string str = "big";
writeln(str.ptr);
str.replace(`i`,`a`);
writeln(str.ptr);

得到下一个输出:

42E080
42E080

所以它显示了相同的地址。为什么呢?

2 个答案:

答案 0 :(得分:2)

您在代码中犯了一个简单的错误:

  

str.replace(" I""&#34);

str.replace 返回替换完成的新字符串,它实际上并不替换现有变量。因此,请尝试str = str.replace("i", "a");查看更改。

但是你也对分配做了一个过于笼统的陈述:

  

所以对字符串处理的每个操作都有内存分配。

这是错误的,很多操作都不需要分配新的内存。任何可以切片现有字符串的东西都会这样做,避免需要新的内存:

import std.string;
import std.stdio;

void main() {
        string a = "  foo  ";
        string b = a.strip();
        assert(b == "foo"); // whitespace stripped off...

        writeln(a.ptr);
        writeln(b.ptr); // but notice how close those ptrs are
        assert(b.ptr == a.ptr + 2); //  yes, b is a slice of a
}
如果实际没有替换,

replace也将返回原始字符串:

string a = "  foo  ";
string b = a.replace("p", "a"); // there is no p to replace
assert(a.ptr is b.ptr); // so same string returned

索引和迭代不需要新的分配(当然)。信不信由你,但有时甚至附加都不会分配,因为切片末尾可能还有一些内存尚未使用(尽管通常会这样)。

还有各种函数返回范围对象,这些对象在迭代时进行更改,从而避免分配。例如,代替replace(a, "f", "");,您可能会执行类似filter!(ch => ch != 'f')(a);和循环的操作,除非您要求,否则不会分配新字符串。

所以它比你想象的要细致得多!

答案 1 :(得分:0)

在D中,所有数组都是长度+指向数组值开头的指针。这些通常存储在堆栈中,恰好就是RAM。

当你去一个变量的地址(在函数体中)时,你真正在做的是获得一个指向堆栈的指针。

要获取数组值的地址,请使用.ptr。 因此,将&str替换为str.ptr,您将获得正确的输出。