求 String 轉換至 PChar 的函數(50分)

procedure TForm1.Button1Click(Sender: TObject);
var
s:pchar;
ss:string;
begin
ss:='saffgsd';
s:=pchar(ss);
showmessage(s);
end;
 
这么简单的问题,竟然这么多争论,看来基础知识也应当巩固呀!
string是Delphi特有的类型(相对C),不用#0作为结尾。
PChar类似于C中的Char *以#0作为结尾。
当string中包含#0时,如果用Pchar(AString)转换,并且访问转换后的结果就会造成丢失。
如果不想丢失,就要用System.Move()(具体参看帮助)
需要注意的是,Move之后如果当作Pchar来访问,还是会丢失,因为Pchar是以#0作为结尾的,
切记,切记!
 
我用过function StrPas(const Str: PChar): string;绝对没问题,就是把pchar转换成
pascal形式的string.
 
plaw 兄說的很對, string 並不只是一個指向字串的指標,它還擁有一些
delphi 內部機制的功能,如參考數量,以決定是否消滅此字串。

問題便在這裡了,如果是 string 指向 string ,問題並不大,

a:='abcdef';
b:=a
// 並無實際拷貝動作,只是指標指向而已。
b[1]:='0'
// 當有實際修改內容時,此時才會開始複製另一區塊給 b
// 所以結果 a='abcdef' , b='0bcdef'

delphi 會自動處理好這些事宜!

而當 string 要轉換給 pchar 時,問題便產生了,一些函數的所謂轉換
只是指向該字串區塊而已,但,該字串卻無增加參考數量,所以,當
參考數量=0 時,該字串自動消滅,而 pchar 此時便指向一個已消滅的記憶體
空間,故會引發違法存取的例外!

而另一些函數則算是舊時代產物,當 string 內含 #0 ,複製過程就只複製到這裡而已,
開什麼玩笑, pchar 只是一種 pointer 而已,只是單位為 char ,但現在我是要從
string --> pchar ,就應該要考慮 string 可內含 #0 ,所以應要全數複製過去才行。


我再度試了一下使用 move ,可行,但還是引發 EInvaildPointer 錯誤!不知問題在哪。
 
procedure TfrmMain.FormCreate(Sender: TObject);
var
p:pChar;
s:string;
begin
s:='aadfdfdfdf';
getmem(p,50);
strpcopy(p,s);
end;
 
to eve:

不行,strpcopy 也是只拷貝到 #0 而已。


procedure TForm1.Button2Click(Sender: TObject);
var
p:pchar;
const
source : string='0123456789'+#0#0+'abc'
// 共 15 bytes
begin
getmem(p,50);
strpcopy(p,source);

try
ShowMessage(p[12])
// 應該顯示 'a' 結果沒有 --> 錯誤
ShowMessage(source[13])
// 顯示 'a' --> 正確
finally
FreeMem(P);
end;
end;
 
我就不说了,直接给几分算了
 
实际上StrPCopy等函数已经够用了!
当然,需要的时候,翻翻帮助不久行了。
给分吧!!!
 
这确实是一个高级的小问题,看了几位的回答,有的分析的很透,学到不少的东东。
我看来自:plaw, 时间:2001-9-10 10:18:00, ID:618227
这么简单的问题,竟然这么多争论,看来基础知识也应当巩固呀!
string是Delphi特有的类型(相对C),不用#0作为结尾。
PChar类似于C中的Char *以#0作为结尾。
当string中包含#0时,如果用Pchar(AString)转换,并且访问转换后的结果就会造成丢失。
如果不想丢失,就要用System.Move()(具体参看帮助)
需要注意的是,Move之后如果当作Pchar来访问,还是会丢失,因为Pchar是以#0作为结尾的,
切记,切记!

plaw说得很对哦。想必是高手吧!
 
这样好不好:
p:=@Source[1];
ShowMessage(p)
//'0123456789' ShowMessage(PChar(@p[0]))一样结果
ShowMessage(p[12])
//'a'
ShowMessage(PChar(@p[12]))
//'abc' 但这可能会有问题,因为Source中abc之后的内存字节到底是不是#0难说啊.
p也不用分配内存了,但若将P当作参数来传递,要注意其所指向内存块的SIZE应为Length(Source).

我这样说对不对?
 
maming说:
plaw说得很对哦。想必是高手吧!
plaw说:
不对不对!俺不是高手。所谓学的越多,发现自己懂得越少。
俺觉得自己也就是刚入门的水平。
 
可惜 StrPCopy 還是無法解決我的問題(可看看上面的討論)。

這題並不算是高深的問題,但它很基本,所以我也想要有個確實的答案後再結束!

wolaixue 說的方法有個問題,就是 plaw 講的丟失的問題,一般來說,區域變數的存活
時間是在程序(或函數)內,但如果 string 只在程序前段出現,後半段沒有出現的話,
很可能編譯器在最佳化時就會消滅 string,那 p 就變成了違法存取了。
 
to jiichen
不好意思,其实前面你写的程序我没有好好看,只是在普遍的意义上说了一些。今天看了一下
你的程序改一下就可以了。

procedure TForm1.Button2Click(Sender: TObject);
var
p:pchar;
const
source : string='0123456789'+#0#0+'abc'
// 共 15 bytes
begin
getmem(p,50);
// strpcopy(p,source)
//这句不要了!!!
StrMove(p,PChar(source),Length(source))
//OK!此处不能用Move,因为string类型有特殊的存储
try
ShowMessage(p[12])
// 應該顯示 'a' 結果沒有 --> 錯誤
ShowMessage(source[13])
// 顯示 'a' --> 正確
finally
FreeMem(P);
end;
end;
 
[red]这要看你用的 D 是什么版本。[/red]
[black]在 D4 以后,String 和 Pchar 已经可以直接转换了。这是因为:
在 D4 以后版本,String 已经是一个指针了,这和 PChar 是一样的。
但在 Delphi 中具有强类型特征,所以你在 string 转为 Pchar 时,
必须用 PChar(String) 这样的强制转换,编译器才认可。
另外,一旦由 string 转为 Pchar ,就脱离了生存期自管理,如果不想
有未释放的内存,你就必须自己编程释放 pchar ,或再转为 String。[/black]
 
就用PChar(String)就可以了嘛
 
to 小雨哥:
之前寫程式時有發生過一次莫名其妙的違法存取,便是由於 string->pchar 。


感謝各位的討論與幫助,謝謝。
 
to 小雨哥:
之前寫程式時有發生過一次莫名其妙的違法存取,便是由於 string->pchar 。


感謝各位的討論與幫助,謝謝。
 
多人接受答案了。
 
顶部