請問 Pchar 是怎面的型態啊 ? |
答題得分者是:cashxin2002
|
lanbome
一般會員 發表:46 回覆:28 積分:14 註冊:2003-07-03 發送簡訊給我 |
|
lanbome
一般會員 發表:46 回覆:28 積分:14 註冊:2003-07-03 發送簡訊給我 |
|
cashxin2002
版主 發表:231 回覆:2555 積分:1937 註冊:2003-03-28 發送簡訊給我 |
您好﹗ 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 發送簡訊給我 |
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
引言: 謝謝你歐,連續回答了我二個問題我的天阿!非常錯誤的觀念!完全不懂程式運作原理的回答! 結果你的程式還給妳矇對,沒出錯 是因為妳不懂?還是亂回答了事?還是要怪 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 發送簡訊給我 |
|
cashxin2002
版主 發表:231 回覆:2555 積分:1937 註冊:2003-03-28 發送簡訊給我 |
|
syntax
尊榮會員 發表:26 回覆:1139 積分:1258 註冊:2002-04-23 發送簡訊給我 |
是阿!這文章我可是改了十幾次,如果看到第一次的,也許會有人抓狂,不過還好大家修養都很好,因為"因為知道真相"而生氣是划不來的,多生氣一場,真實不會因此而改變 但是若是為了真理而爭執,那是值得的,因為真理是越辯越明 不過也許是民族性的關係,我們通常是會打起來,然後再也不講話! 不像西方人,當真理明顯後,他們會停止爭執,並為知道真理而高興,也不會因此而對對方有所記恨,或討厭,因為當他們爭執時,是爭個真相,不是為爭而爭,也不是為仇視對方而爭 以前我們東方爭到最後都變成在仇視對方,至於真理早就放到一邊了,不過,現在的我們也進步很多了,所以台灣今天才會如此繁榮,比對岸的人發展的快,因為對岸花太多時間在文革等為仇視而爭的事上面,如果沒有,那也許我們現在早就比不上對岸了哩!更不用說要跟西方競爭了
|
gglee
一般會員 發表:0 回覆:2 積分:0 註冊:2003-11-27 發送簡訊給我 |
請問 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 發送簡訊給我 |
記得在很早以前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 發送簡訊給我 |
以下純屬個人觀點
======>初始階段 變數本身所佔用記憶體(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, 註解 無‧
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |