2013-02-22 74 views
0

我在D中編寫了一個trie,我希望每個trie對象都有一個指向某些數據的指針,如果該節點是trie中的終端節點,則該數據具有非NULL值,否則爲NULL。數據的類型在創建trie之前是不確定的(在C中,這將通過void *完成,但我打算使用模板來完成),這是爲什麼指向堆對象是理想的原因之一。如何在D堆中創建一個字符串?

這需要我最終在堆上創建我的數據,在此點可以指向trie節點。試驗中,似乎new執行此任務,就像它在C++中一樣。但是由於某些原因,這會導致字符串失敗。下面的代碼工作:

import std.stdio; 

void main() { 
    string *a; 
    string b = "hello"; 
    a = &b; 
    writefln("b = %s, a = %s, *a = %s", b, a, *a); 
} 
/* OUTPUT: 
b = hello, a = 7FFF5C60D8B0, *a = hello 
*/ 

然而,這種失敗:

import std.stdio; 

void main() { 
    string *a; 
    a = new string(); 
    writefln("a = %s, *a = %s", a, *a); 
} 
/* COMPILER FAILS WITH: 
test.d(5): Error: new can only create structs, dynamic arrays or class objects, not string's 
*/ 

是怎麼回事?我如何在堆上創建字符串?

P.S.如果有人編寫D編譯器正在讀取這個,那麼「string's」中的撇號是一個語法錯誤。

+0

「PS如果有人寫d編譯器讀這篇文章, 「字符串」中的撇號是一個語法錯誤。「不,這是故意的。如果需要,應該使用原始字符串。 auto mystring = \'string's \'; – 0b1100110 2013-02-22 23:22:06

回答

2

請記住,string只是immutable(char)[]。所以你不需要指針,因爲string已經是一個動態數組了。

至於創建它們,你只是做new char[X],而不是new string

0

字符串內容已在堆上,因爲字符串是動態數組。然而,就你而言,最好使用char動態數組,因爲你需要可變性。

import std.stdio; 

void main() { 
    char[] a = null; // redundant as dynamic arrays are initialized to null 
    writefln("a = \"%s\", a.ptr = %s", a, a.ptr); // prints: a = "", a.ptr = null 
    a = "hello".dup; // dup is required because a is mutable 
    writefln("a = \"%s\", a.ptr = %s", a, a.ptr); // prints: a = "hello", a.ptr = 7F3146469FF0 
} 

請注意,您實際上並不持有該數組的內容,而是其中的一部分。該數組由運行時處理,並分配在堆上。 關於這個問題的一個很好的閱讀是這篇文章http://dlang.org/d-array-article.html

5

字符串總是分配在堆上。對於任何其他動態數組,這是相同的(T[],string只是immutable(char)[]的別名)。

如果你只需要一個指針有兩種方法可以做到這一點:

auto str = "some immutable(char) array"; 
auto ptr1 = &str; // return pointer to reference to string (immutable(char)[]*) 
auto ptr2 = str.ptr; // return pointer to first element in string (char*) 

如果你需要指向空字符串,使用:

auto ptr = &""; 

請記住,你不能改變字符串中任何單個字符的值(因爲它們是immutable)。如果你想在字符串的字符操作使用:

auto mutableString1 = cast(char[])"Convert to mutable."; // shouldn't be used 
// or 
auto mutableString2 = "Convert to mutable.".dup; // T[].dup returns mutable duplicate of array 

一般來說,你應該避免指針,除非你絕對知道你在做什麼。從存儲器的角度來看,任何指針都需要4B(8B爲x64機器)的內存,但是如果你使用的是指向數組的指針,那麼如果指針不爲空,那麼內存中有12B(+數據數組)使用。 4B如果來自指針而8B則來自引用數組,因爲數組引用是由兩個指針組成的。數組中的第一個和最後一個元素。

+0

你不應該從'string'轉換爲'char []',而是直接使用'char []',(你可以用'assumeUnique'來更好地轉換) – 2013-02-22 20:11:58

+0

你是對的。由於字符串數據在引用之間共享這一事實,因此從字符串轉換是潛在的危險。安全方法應該使用'dup'屬性(添加到原始答案中)。 – Marmyst 2013-02-22 20:44:28

+0

你可能還想提及idup以及返回一個不可變的副本 – 2013-02-22 22:17:57

0

如果你只能使用只有一個指針,你不想使用Marmyst的答案的建議(&str在他的例子創建到您可能不希望棧參考,str.ptr損失大約字符串的長度信息d字符串不總是零終止的),你可以這樣做:

,你能想到d陣列(因此字符串)與數據指針和長度成員的struct Remeber:

struct ArraySlice(T) 
{ 
    T* ptr; 
    size_t length; 
} 

所以當處理數組數組的內容總是在堆上,但是ptr/lengt h組合類型是值類型,因此通常保留在堆棧上。我不知道爲什麼,編譯器不會允許您創建使用新堆中值類型,但你總是可以做手工:

import core.memory; 
import std.stdio; 

string* ptr; 

void alloc() 
{ 
    ptr = cast(string*)GC.malloc(string.sizeof); 
    *ptr = "Hello World!"; 
} 

void main() 
{ 
    alloc(); 
    writefln("ptr=%s, ptr.ptr=%s, ptr.length=%s, *ptr=%s", ptr, ptr.ptr, ptr.length, *ptr); 
} 
相關問題