線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:4202
推到 Plurk!
推到 Facebook!

請問 Pchar 是怎面的型態啊 ?

答題得分者是:cashxin2002
lanbome
一般會員


發表:46
回覆:28
積分:14
註冊:2003-07-03

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-01-19 11:53:53 IP:61.220.xxx.xxx 未訂閱
請問 Pchar 是怎面的型態啊 ,請回答一下嗎 ?
lanbome
一般會員


發表:46
回覆:28
積分:14
註冊:2003-07-03

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-01-19 11:56:19 IP:61.220.xxx.xxx 未訂閱
打太快了,是怎樣的型態,有問能回答我一下嗎?
cashxin2002
版主


發表:231
回覆:2555
積分:1937
註冊:2003-03-28

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-01-19 12:16:42 IP:63.84.xxx.xxx 未訂閱
您好﹗    PChar是由一個或多個Char字元的組合﹐先來解釋一下Char﹐Char是指0~255個ASCII碼﹐通常我們從String字串中可抓出字元Char﹐例﹕ String[I] := Char; 多個字元Char的組合就是PChar的形態了﹐通常可以使用到的範圍很廣﹐一般的字串String中都允許使用﹐例﹕
Var
  Str : String;
begin
  Str := 'Delphi is good!';
  ShowMessage(IntToStr(Length(String)));
end;
以上程式即可Show出Str字串的長度﹐其中的Str宣告為String形態﹒我們也可宣告為PChar形態﹐例﹕
Var
  Str : PChar;
begin
  Str := 'Delphi is good!'
  ShowMessage(IntToStr(Length(String)));
end;
此處即宣告為PChar形態﹐Length同樣接受PChar形態 但有些函數是只能使用PChar形態的﹐如MessageBox就是典型的例子﹕
Var
  Str : String;
begin
  Str := 'Delphi is good!';
  Application.MessageBox(PChar(Str), '對話方塊', MB_OK);
end;
從上例中即可看出在MessageBox的宣告中﹐只接受PChar形態﹐而不接受String形態﹐所以﹐需要對String形態的字串進行轉換﹐轉換的方法同上﹐即﹕PChar(String); 參考看看﹗ ===================== 努力,相信會獲得美麗! 忻晟
------
忻晟
lanbome
一般會員


發表:46
回覆:28
積分:14
註冊:2003-07-03

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-01-19 12:44:42 IP:61.220.xxx.xxx 未訂閱
謝謝你歐,連續回答了我二個問題
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-01-25 22:00:35 IP:203.203.xxx.xxx 未訂閱
多貼的!刪除內容 發表人 - syntax 於 2004/01/25 22:20:20
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-01-25 22:18:48 IP:203.203.xxx.xxx 未訂閱
多貼的!刪除內容 發表人 - syntax 於 2004/01/25 22:20:48
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-01-25 22:19:03 IP:203.203.xxx.xxx 未訂閱
引言: 謝謝你歐,連續回答了我二個問題
我的天阿!非常錯誤的觀念!完全不懂程式運作原理的回答! 結果你的程式還給妳矇對,沒出錯 是因為妳不懂?還是亂回答了事?還是要怪 Delphi 設計得太好呢? 亂問!亂答!亂給分!加上亂學習!這下可好了...... . 隨便參考看看!總有一天會出事的!要小心才是ㄋㄟ . . . . . . . . . . . 補充一下正確解答! 1.PChar 是一種指標型別,是哪種指標型別呢?很明顯,是 Char 的型別 Char 指的是一個字元,在 PC 上,一個字元的大小是 1 Byte,值域由 0 ~ 255 即是 0x00 ~ 0xFF,也就是所謂的 255 個 ASCII 碼,其中有些碼在螢幕上是不以顯示的,如 0x0A or 0x0D 所以 PChar 指的是一個指向一個字元的記憶體指標,他是指標 2.String 是 Pascal 特有的型別,用於處理字串,其實際上是一個指向一個記錄著一個動態 PChar 陣列開頭的指標的指標,然後那個位置又紀錄著該動態動態 PChar 陣列的起使位置,妳可以簡單的想像是一通電話轉接了兩次,其中 Delphi 就是接線生 就因為 Delphi 幫我們多做了這些事,所以 Delphi 在字串處理上,比 C 在[使用的直覺]上方便許多! 如 妳可以用 Str1 := Str2 Str3; 但是 C 要用 Strcat(S1,S2) 等函數的方式來處理,不如 Delphi 直覺 3.因為 Windows/C 是採用 Char * (即是指 Pascal 的 PChar),並無所謂的字串,在 PChar 的世界下,若是要使用字串,就是要宣告一個字元的陣列,來記錄一串字,一個陣列位置記錄一個字,形成所謂的字串,而所宣告的變數是一個 PChar(在 C 是用 Char * ...),紀錄著該陣列的開頭位置(會 C 語言的就應該很清楚),而 Delphi 為了與 Windows 接軌,會自己幫我們作 String to PChar 的轉換,這時妳應該知道Windows 根本沒有 PChar 這種東西,PChar 是 Delphi 為了與 Windows 接軌而自己命名的一種型別,代表的是 C 的 Char * ..,同時有時為了設計與執行上效率的問題,也直接使用 char pointer,所以我們才會在使用 Delphi 函示/程序 或 Windows API 時需要將 String 轉成 pointer char,可以想成將轉接兩次的電話,轉成直撥,所以轉換出來的 PChar 是直接指向該字串的記憶體位置開頭的一個變數,但不管是直撥或是轉接,都是在編譯器層面的技術,編成程式以後都一樣,都是相同的動作,由字串所在的記憶體位置開頭依序取出字元成為一個字串 .(編成的程式碼可能會用一個一個取出或直接用記憶體拷貝之方式,是哪些方法還要參考所寫的程式上下之程式碼,以求最佳化) 4.那為什麼宣告成 String 與 PChar 都會對呢? 那是因為 Delphi 幫妳宣告了 PChar 所需要的記憶體,但是妳要是使用了兩次以上,就會出問題了,因為妳沒有釋放所有字串所使用的記憶體 ex: in procedure Str := 'First string'; {This will be forgot to unlocate memory By Delphi} show the Str Str := 'Use str for second string'; {This will be unlocated memory by Delphi} show the Str end procedure Delphi 會幫妳釋放 'Use str for second string' ,但是 'First string' 將永遠留在記憶體中,造成 Memory leak..... 這是很可怕的缺失,程式會常常出現找不到的錯誤,尤其是人命關天的程式,如醫院的心肺維持系統因此 Memory leak 而造成記憶體用盡,進而當機,那使用該機器的人也會永遠當機,這樣嚴重嗎?你自己想! 所以囉,不要對 Pointer 掉以輕心,並要有正確的認識 5.順便一題,在支援 .Net後;PChar 在 Delphi 7 以上已經是 unsafe type Delphi 建議不使用 發表人 - syntax 於 2004/01/25 22:21:43 四、五次修改,現在文中應該沒有錯字或用語,如有請勿見怪,若語氣太重,請包涵!全文無"重的語氣"的意思 剛發現是版主貼的解答!版大!拉妳後腿勿見怪,因為站上一年到頭都有類似的文章,與一堆"為何我的程式會出錯?",而錯在Memory leak又不少,恰好如果使用者看了妳的回文,宣告Str: PChar,又用了一堆...Str := 'xxx';,那就不好了,趕快貼上我不堪的認知 發表人 - syntax 於 2004/01/25 22:36:24
kj68215
初階會員


發表:47
回覆:91
積分:27
註冊:2003-08-09

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-01-26 07:39:44 IP:61.231.xxx.xxx 未訂閱
真想不到hahalin大大也有這段的糗事呀?! < > 所謂說者無心,聽者有意! 所以囉,謹慎言行粉重要地唷!!< > ----------------------- 請多多指教啦!!^^
------
-----------------------
請多多指教啦!!^^
cashxin2002
版主


發表:231
回覆:2555
積分:1937
註冊:2003-03-28

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-01-26 09:19:41 IP:63.84.xxx.xxx 未訂閱
syntax, 您好﹗    感謝您的指正﹐讓小弟領悟到正确的觀念﹒    再次感謝﹗    ===================== 努力,相信會獲得美麗! 忻晟
------
忻晟
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-01-26 11:28:54 IP:203.203.xxx.xxx 未訂閱
是阿!這文章我可是改了十幾次,如果看到第一次的,也許會有人抓狂,不過還好大家修養都很好,因為"因為知道真相"而生氣是划不來的,多生氣一場,真實不會因此而改變 但是若是為了真理而爭執,那是值得的,因為真理是越辯越明 不過也許是民族性的關係,我們通常是會打起來,然後再也不講話! 不像西方人,當真理明顯後,他們會停止爭執,並為知道真理而高興,也不會因此而對對方有所記恨,或討厭,因為當他們爭執時,是爭個真相,不是為爭而爭,也不是為仇視對方而爭 以前我們東方爭到最後都變成在仇視對方,至於真理早就放到一邊了,不過,現在的我們也進步很多了,所以台灣今天才會如此繁榮,比對岸的人發展的快,因為對岸花太多時間在文革等為仇視而爭的事上面,如果沒有,那也許我們現在早就比不上對岸了哩!更不用說要跟西方競爭了
gglee
一般會員


發表:0
回覆:2
積分:0
註冊:2003-11-27

發送簡訊給我
#11 引用回覆 回覆 發表時間:2007-09-29 11:10:24 IP:220.130.xxx.xxx 訂閱
請問 syntax 大大,
你所說的 「'First string' 將永遠留在記憶體中」,要如何驗證呢?
我用 delphi7 試了一下,看不出來 memory leak 的現象耶,
請教一下是否我試的方式不太對呢?

procedure TForm1.Button1Click(Sender: TObject);
var
s: PChar;
i: integer;
begin
Button1.Caption := 'Running...';

repeat
for i := 1 to 100000000 do
s := 'MEM LEAK TEST';
Application.ProcessMessages;
until CheckBox1.Checked;

Button1.Caption := 'Stopped';
end;

用它跑了2個小時後,工作管理員看到程式memory size沒有變大,
另外加了 MemCheck 也沒有出現 leak 的訊息…

jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#12 引用回覆 回覆 發表時間:2007-09-29 16:48:47 IP:210.66.xxx.xxx 訂閱

記得在很早以前D2的書上看過, Delphi對於字串的實作,是使用一個引用計數器 (Reference Count).

[code delphi]
procedure TfrmTestMain.Button4Click(Sender: TObject);
var
S1, S2: string;

procedure ADD_MESSAGE(Step: string);
begin
ListBox1.Items.Add('');
ListBox1.Items.Add('======>' Step );
ListBox1.Items.Add('變數本身所佔用記憶體(S1)=' IntToStr(SizeOf(S1)));
ListBox1.Items.Add('變數本身所佔用記憶體(S2)=' IntToStr(SizeOf(S2)));
ListBox1.Items.Add('變數所在位址(S1)=' IntToStr(Integer(@S1)));
ListBox1.Items.Add('變數所在位址(S2)=' IntToStr(Integer(@S2)));
ListBox1.Items.Add('指向記憶體位址(S1)=' IntToStr(Integer(S1)));
ListBox1.Items.Add('指向記憶體位址(S2)=' IntToStr(Integer(S2)));
ListBox1.Items.Add('字串長度(S1)=' IntToStr(Length(S1)));
ListBox1.Items.Add('字串長度(S2)=' IntToStr(Length(S2)));
ListBox1.Items.Add('-------------------------------------');
end;

begin
{1} ADD_MESSAGE('初始階段');
{2} S1 := '01234';
ADD_MESSAGE('After S1 := ''01234''');

{3} S2 := S1;
ADD_MESSAGE('After S2 := S1');

{4} S2 := '0123456789';
ADD_MESSAGE('After S2 := ''0123456789''');

{5} S1 := '';
S2 := '';
ADD_MESSAGE('After S1 := ''''; S2 := ''''');

end;
[/code]
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#13 引用回覆 回覆 發表時間:2007-09-29 18:12:32 IP:123.193.xxx.xxx 訂閱
以下純屬個人觀點

======>初始階段
變數本身所佔用記憶體(S1)=4
變數本身所佔用記憶體(S2)=4
變數所在位址(S1)=1242080
變數所在位址(S2)=1242076
指向記憶體位址(S1)=0
指向記憶體位址(S2)=0
字串長度(S1)=0
字串長度(S2)=0
-------------------------------------
初始階段, 區域變數 S1, S2 在不同的位址, 各佔用 4 Byte的記憶體

======>After S1 := '01234'
變數本身所佔用記憶體(S1)=4
變數本身所佔用記憶體(S2)=4
變數所在位址(S1)=1242080
變數所在位址(S2)=1242076
指向記憶體位址(S1)=4528528
指向記憶體位址(S2)=0
字串長度(S1)=5
字串長度(S2)=0
-------------------------------------
'01234' -> 在記憶體中配置 長度=5 的空間, 並將值填入,
->傳回記憶體位址, 並指定給 S1存放.
->'01234' 的 ReferenceCount = 1.

======>After S2 := S1
變數本身所佔用記憶體(S1)=4
變數本身所佔用記憶體(S2)=4
變數所在位址(S1)=1242080
變數所在位址(S2)=1242076
指向記憶體位址(S1)=4528528
指向記憶體位址(S2)=4528528
字串長度(S1)=5
字串長度(S2)=5
-------------------------------------
將S1指向的位址, 指定給 S2, 此時 S1, S2 指向同一個字串,在記憶體中只有一份 '01234'
'01234' 的ReferenceCount 加 1, (ReferenceCount = 2).

======>After S2 := '0123456789'
變數本身所佔用記憶體(S1)=4
變數本身所佔用記憶體(S2)=4
變數所在位址(S1)=1242080
變數所在位址(S2)=1242076
指向記憶體位址(S1)=4528528
指向記憶體位址(S2)=4528596
字串長度(S1)=5
字串長度(S2)=10
-------------------------------------
當 S2 指向的字串值改變, 新配置的記憶體區塊'0123456789' 的 ReferenceCount = 1,
'01234' 的 ReferenceCount 減 1 (ReferenceCount=1).

======>After S1 := ''; S2 := ''
變數本身所佔用記憶體(S1)=4
變數本身所佔用記憶體(S2)=4
變數所在位址(S1)=1242080
變數所在位址(S2)=1242076
指向記憶體位址(S1)=0
指向記憶體位址(S2)=0
字串長度(S1)=0
字串長度(S2)=0
-------------------------------------
執行 S1 := '' 及 S2 := '' 後, 上述兩區塊的ReferenceCount都被減 1,
當 ReferenceCount = 0時, 原先配置的記憶體應該會被釋放.

即使不執行 S1 := '' 及 S2 := '', 當區域變數離開其可視範圍, 變數會失效並回收,
同樣的, ReferenceCount 也會減少.


NOTE: 在我的電腦中, 每次Click Button 的執行結果都一樣.
除了字串型態外, 還有其他的型別也要注意其記憶體
的配置與釋放, 哪些是Delphi 會幫你處理的, 哪些不會.


相關主題:
http://delphi.ktop.com.tw/board.php?cid=30&fid=70&tid=90458

編輯記錄
jow 重新編輯於 2007-09-29 18:18:38, 註解 無‧
系統時間:2024-04-24 9:23:23
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!