在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
所以它显示了相同的地址。为什么呢?
答案 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
,您将获得正确的输出。