Delphi字符串與字符數組之間的轉換(初始化的重要性)


緊接着上篇博客講解的內容:

  將Char型數組轉換為string類型還有下面的這種方法

  但是我在測試的時候遇到了一些問題,並在下面進行了解釋和總結

 

 

先說出我的總結

  其實我們在學習編程的時候(比如我之前學習C的時候),一直有書或者博客上有建議說聲明一個變量之后,一定要初始化,否則可能出現一些意想不到的錯誤。雖然這里的buf 也進行了初始化,但是初始化不完全(並沒有考慮到字符串應該以#0 作為結尾),所以就出現了這樣的問題。

  另外,在編程的時候,難免因為很多問題沒有考慮到而出現這樣那樣的問題,這個時候不要瞎猜,可以為自己的程序設置幾個斷點來調試一下、去看看運行時候的變量的值……

    Delphi的調試就類似與上面所講的,更詳細的可以看http://www.cnblogs.com/xumenger/p/4443975.html

    C/C++里面也有,我比較喜歡Linux環境下的GDB調試器,GDB教程參考:http://www.cnblogs.com/xumenger/p/4214068.html

 

 再開始講解整個過程

  Char數組與String存儲方式一樣(還是有不一樣的,具體的String的存儲結構見:http://www.cnblogs.com/xumenger/p/4427957.html),只不過string是以 '/0' 結尾的char數組(這樣理解是可以的,但是不是很精確)。所以可以把Char數組強制轉換為string類型。

程序一

procedure TForm1.Button1Click(Sender: TObject);
var
  buf: array[0..255] of Char;
  s :string;
  i: Integer;
begin
  for i:=0 to 10 do
    buf[i]:= 'f';

  s:= string(buf);

  ShowMessage(s);
end;

 

  編譯之后,點擊按鈕會看到這樣的效果

 

程序二

  但是,如果 buf 數組中間有某一位是 '/0'(在Delphi里面是 #0),轉換時以第一個出現的'/0'前面的內容轉換為s的內容,如果第一個字符即為'/0'(即#0),buf[0]=char(0),則s的內容為空字符串。下面有一個例子

procedure TForm1.Button1Click(Sender: TObject);
var
  buf: array[0..255] of Char;
  s :string;
  i: Integer;
begin
  for i:=0 to 10 do
    buf[i]:= 'f';

  buf[11]:= #0;

  for i:=12 to 15 do
    buf[i]:= 'c';

  s:= string(buf);

  ShowMessage(s);
end;

 

  編譯之后,點擊按鈕會看到這樣的效果。字符串s 只會有字符數組的 #0 之前的內容,#0 之后的就不會有,因為string是以#0 結尾的

 

程序三

  但是還要注意一個問題,我在編寫這樣的代碼的時候

procedure TForm1.Button1Click(Sender: TObject);
var
  buf: array[0..255] of Char;
  s :string;
  i: Integer;
begin
  for i:=0 to 10 do
    buf[i]:= 'f';

  buf[11]:= 'p';

  for i:=12 to 15 do
    buf[i]:= 'c';

  s:= string(buf);

  ShowMessage(s);
end;

  出現下面的問題

  為什么我將buf 的從 0到 10賦值為'f',11賦值為'p', 12到15賦值為'c',這些顯示都沒有問題,但是為什么后面多了那幾個亂七八糟的字符

  所以設置斷點,進行單步調試查看到底是為什么

  如圖,在  s:= string(buf); 這行設置斷點(F5)

  再按F9運行,在這行停住,再看buf的內容(Ctrl+鼠標左鍵),如下圖

  可以看到buf的元素從0 到15都確實是自己在程序中賦值的內容,但是為什么后面會出現這些亂七八糟的東西,回想第一個程序為什么能正確顯示 fffffffffff,所以又回去將本博客中的第一個程序進行了斷點調試

  還是在  s:= string(buf); 這行設置斷點(F5),如圖

  再按F9運行,到斷點處,再看 buf的值

  確實從0到10是 fffffffffff,11是#0,但是到16開始又有一些亂七八糟的東西出現了。所以就說明了初始化的重要性:進行初始化的內容就會確定是初始化時候的值,而沒有初始化的部分可能是隨機的值,這樣就存在潛在的危險,因為對於不確定的東西就很難進行明確的控制

 

  但是還有一種情況,就是將一個char型數組的所有元素都賦值為非 #0 的字符,在進行類型轉換為string 類型會出現什么情況呢

程序四

procedure TForm1.btn1Click(Sender: TObject);
var
  s: string;
  a: array[0..2] of Char;
  i: Integer;
begin
  for i:=0 to 2 do
    a[i]:= 'j';
  s:= string(a);
  ShowMessage(s[1]+' '+s[2]+ ' '+s[3] +' '+ IntToStr(Integer(s[4])));
end;

  補充:Char數組根據定義可以是從0開始,也可以是從1開始,也可以是從其他任何數開始(這點和C/C++中的數組不同),但是String的字符存儲要從 1 開始

  顯示的結果如圖

  所以可以看出,將一個所有元素都為非 #0 的字符數組,強制轉換為string,那么這個string會拷貝這個元素,並且自動添加一個 #0在string中作為結尾

  如果這個字符數組中某一個元素為 #0 ,那么強制轉化為 string之后,就只會保留#0 及其之前的字符串

 

  使用PChar分配動態內存,並將一個PChar里面的所有元素都賦值為非 #0 的字符,在進行類型轉換為string 類型和上面的效果一樣

procedure TForm1.btn1Click(Sender: TObject);
var
  s: string;
  a: array[0..2] of Char;
  p: PChar;
  i: Integer;
begin
  GetMem(p, 3);
  for i:=0 to 2 do
    p[i]:= 'j';
  s:= string(p);
  ShowMessage(s[1]+' '+s[2]+ ' '+s[3] +' '+ IntToStr(Integer(s[4])));
end;

  

  原因

  在程序三中,我們聲明了字符數組 buf,buf分配了255字節的內存,這時候buf 並沒有顯式聲明,所以buf的內容就是其分配的內存中原來的那些亂七八糟的東西(對本程序是完全沒有意義的),但是第一個程序顯式聲明了從0到10的元素,第三個程序顯示聲明了0 到15 的元素,可是第一個程序的11 個元素及其之后的元素還是原來那些亂七八糟的東西,第三個程序的16個元素及其之后的元素也還是原來那些亂七八糟的東西。

  不過第一個程序比較巧合的是第11 個元素碰巧是 #0,所以在這個程序最終的效果碰巧正確(但是這里是隱藏着隱患的),而第三個程序就沒有那么巧合了,所以就又顯示了一個亂七八糟的字符。這並不是意味着第一個程序正確,只是它比較“幸運”罷了。但是項目開發並不是開玩笑,不能靠巧合和運氣,必須要確定和穩定

  所以不論上面談到的什么情況,要想避免可能出現的錯誤,唯一的原則就是:顯式的聲明想要結束的地方為 #0,這樣就不會出錯了,這樣的代碼就比較可靠,不會因為上面的那種巧合來出現“正確的”效果或者“錯誤的”效果

 

  總結

  首先,其實我們在學習編程的時候,一直有書或者博客上有建議說聲明一個變量之后,一定要初始化,否則可能出現一些意想不到的錯誤。雖然這里的buf 也進行了初始化,但是初始化不完全(並沒有考慮到字符串應該以#0 作為結尾),所以就出現了這樣的問題。在C/C++里面也是和Delphi一樣的。

  另外,在編程的時候,難免因為很多問題沒有考慮到而出現這樣那樣的問題,這個時候不要瞎猜,可以為自己的程序設置幾個斷點來調試一下、去看看運行時候的變量的值……

    Delphi的調試就類似與上面所講的,更詳細的可以看http://www.cnblogs.com/xumenger/p/4443975.html

    C/C++里面也有,我就比較喜歡Linux環境下的GDB調試器,GDB的簡單使用教程,參考:http://www.cnblogs.com/xumenger/p/4214068.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM