全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2184
推到 Plurk!
推到 Facebook!

結構陣列宣告問題

尚未結案
renth555
一般會員


發表:32
回覆:65
積分:19
註冊:2003-02-17

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-10-26 01:21:35 IP:61.56.xxx.xxx 未訂閱
typedef struct{ AnsiString GSET; AnsiString NAME; }DAT; int X=50; DAT AAA[X]; 我的問題在於 [X] 因我還不知結構確定值 要程式跑後才知 X=多少 請問這樣的方法有解嗎
RaynorPao
版主


發表:139
回覆:3622
積分:7025
註冊:2002-08-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-10-26 03:22:53 IP:61.221.xxx.xxx 未訂閱
引言: typedef struct{ AnsiString GSET; AnsiString NAME; }DAT; int X=50; DAT AAA[X]; 我的問題在於 [X] 因我還不知結構確定值 要程式跑後才知 X=多少 請問這樣的方法有解嗎
renth555 你好: 請參考以下的做法 < class="code"> #include "StrUtils.hpp" // 宣告 struct (建議儘量別使用 AnsiString 宣告在 struct 裡面,在某些應 // 用的情況之下會有問題的;建議改用宣告佔有實體記憶體的 char array) typedef struct _MYSTRUCT { char szGSET[64]; char szNAME[64]; } MYSTRUCT; // 假設已經動態取得 iX=50 int iX=50; // 宣告 MYSTRUCT 的指標 MYSTRUCT *pMyStruct=NULL; // 動態配置記憶體給 MYSTRUCT 的指標 pMyStruct=(MYSTRUCT*)new BYTE[iX*sizeof(MYSTRUCT)]; // 養成好習慣,先將動態配置的記憶體每個 BYTE 歸零 ZeroMemory(pMyStruct, iX*sizeof(MYSTRUCT)); // 設定 struct 的值 for(int i=0; iSize=iX*sizeof(MYSTRUCT); ms->Write(pMyStruct, ms->Size); ms->SaveToFile("test.dat"); delete ms; // 釋放記憶體 delete pMyStruct; -- Enjoy Researching & Developing --
------
-- 若您已經得到滿意的答覆,請適時結案!! --
-- 欲知前世因,今生受者是;欲知來世果,今生做者是 --
-- 一切有為法,如夢幻泡影,如露亦如電,應作如是觀 --
tomlee
一般會員


發表:5
回覆:14
積分:18
註冊:2003-10-11

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-10-26 23:41:09 IP:218.167.xxx.xxx 未訂閱
引言:
引言: typedef struct{ AnsiString GSET; AnsiString NAME; }DAT; int X=50; DAT AAA[X]; 我的問題在於 [X] 因我還不知結構確定值 要程式跑後才知 X=多少 請問這樣的方法有解嗎
renth555 你好: 請參考以下的做法 < class="code"> #include "StrUtils.hpp" // 宣告 struct (建議儘量別使用 AnsiString 宣告在 struct 裡面,在某些應 // 用的情況之下會有問題的;建議改用宣告佔有實體記憶體的 char array) typedef struct _MYSTRUCT { char szGSET[64]; char szNAME[64]; } MYSTRUCT; // 假設已經動態取得 iX=50 int iX=50; // 宣告 MYSTRUCT 的指標 MYSTRUCT *pMyStruct=NULL; // 動態配置記憶體給 MYSTRUCT 的指標 pMyStruct=(MYSTRUCT*)new BYTE[iX*sizeof(MYSTRUCT)]; // 養成好習慣,先將動態配置的記憶體每個 BYTE 歸零 ZeroMemory(pMyStruct, iX*sizeof(MYSTRUCT)); // 設定 struct 的值 for(int i=0; iSize=iX*sizeof(MYSTRUCT); ms->Write(pMyStruct, ms->Size); ms->SaveToFile("test.dat"); delete ms; // 釋放記憶體 delete pMyStruct; -- Enjoy Researching & Developing --
    直接改成這樣就好了:    struct DAT
{
  AnsiString GSET;
  AnsiString NAME;
};    用標準函式庫的 vector<> ,就可以解決你的問題。
vector v;    關於 RaynorPao 說的內容,他的寫法是 C 的慣用風格,不是 C   的風格。    在 struct 或 class 裏面放 AnsiString 大多數的情況都比直接用 char [] 好。除非你需要利用該 struct 的記憶體佈局(例如傳送封包,節省記憶體……等),但只有低階程式才這麼做。所謂低階程式就是對機器、作業系統依賴度比比較高的程式,通常都是函式庫作者的工作,沒事不要自找麻煩。    因為 AnsiString 是包裝良好的類別,而 C 字串用的是低階的陣列和指標來操作,這兩者通常是 C/C   程式錯誤的根源,沒必要最好不要用。否則你還要擔心初始化、解構、賦值、拷貝、動態配置等等的問題,太麻煩了。    例如:    pMyStruct=(MYSTRUCT*)new BYTE[iX*sizeof(MYSTRUCT)];
delete pMyStruct;    馬上就有一個很嚴重的錯誤,應該是:    delete [] pMyStruct;     才對,少寫 [] 編譯不會出錯,但執行時可能會產生大問題。另,就算真的要動態配置,這樣寫就好了:    pMyStruct = new BYTE[iX*sizeof MYSTRUCT];    手動強制轉型是多餘的(也不好)。    
renth555
一般會員


發表:32
回覆:65
積分:19
註冊:2003-02-17

發送簡訊給我
#4 引用回覆 回覆 發表時間:2003-10-27 17:56:29 IP:61.56.xxx.xxx 未訂閱
typedef struct{ AnsiString aaa; AnsiString bbb; }DAT; int X=50; DAT *z=NULL; z =(DAT*)new BYTE[X*sizeof(DAT)]; //動態配置記憶體指標 ZeroMemory(z,X*sizeof(DAT)); //動態配置的記憶體每個 BYTE 歸零 z[1].aaa="abc"; z[0].aaa="xyz"; 這樣真的就可以了謝謝 但tomlee 前輩這樣宣告不會過為什麼 pMyStruct = new BYTE[iX*sizeof MYSTRUCT]; RaynorPao 前輩可以詳細為我解說下面語法意思嗎 new BYTE[X*sizeof(DAT)] ----> 比如結果 BYTE[50x10] (DAT*) ------> 強制轉換 (不懂) z=???? z =(DAT*)new BYTE[X*sizeof(DAT)]; //動態配置記憶體指標 ZeroMemory(z,X*sizeof(DAT)); //動態配置的記憶體每個 BYTE 歸零
renth555
一般會員


發表:32
回覆:65
積分:19
註冊:2003-02-17

發送簡訊給我
#5 引用回覆 回覆 發表時間:2003-10-27 18:05:56 IP:61.56.xxx.xxx 未訂閱
void __fastcall TForm1::Button1Click(TObject *Sender) { typedef struct{ AnsiString aaa; AnsiString bbb; }DAT; int X=50; DAT *z=NULL; z =(DAT*)new BYTE[X*sizeof(DAT)]; ZeroMemory(z,X*sizeof(DAT)); z[0].aaa="abc"; z[1].aaa="xyz"; z[100].aaa="vvvv"; ----------------------->為什麼可以 ShowMessage(z[100].aaa); delete z; } 這樣也可以 這樣就不可以 delete [] z;
taishyang
站務副站長


發表:377
回覆:5490
積分:4563
註冊:2002-10-08

發送簡訊給我
#6 引用回覆 回覆 發表時間:2003-10-27 18:55:49 IP:140.135.xxx.xxx 未訂閱
renth555您好: 請參考下面連結讓您的程式碼比較方便閱讀,謝謝您的配合 < href="http://delphi.ktop.com.tw/topic.php?TOPIC_ID=39608">http://delphi.ktop.com.tw/topic.php?TOPIC_ID=39608
RaynorPao
版主


發表:139
回覆:3622
積分:7025
註冊:2002-08-12

發送簡訊給我
#7 引用回覆 回覆 發表時間:2003-10-27 20:53:48 IP:61.221.xxx.xxx 未訂閱
renth555 你好:
引言: typedef struct{ AnsiString aaa; AnsiString bbb; }DAT; int X=50; DAT *z=NULL; z =(DAT*)new BYTE[X*sizeof(DAT)]; //動態配置記憶體指標 ZeroMemory(z,X*sizeof(DAT)); //動態配置的記憶體每個 BYTE 歸零 z[1].aaa="abc"; z[0].aaa="xyz"; 這樣真的就可以了謝謝 但tomlee 前輩這樣宣告不會過為什麼 pMyStruct = new BYTE[iX*sizeof MYSTRUCT];

(1)因為 pMyStruct 的型態被宣告為 MYSTRUCT 的指標,因此如果這樣子寫,在
   編譯的時候會被 compiler 視為不合法的語法,所以,才會需要強制轉型為
   MYSTRUCT 的指標,如下:
   pMyStruct=(MYSTRUCT*)new BYTE[iX*sizeof(MYSTRUCT)];
RaynorPao 前輩可以詳細為我解說下面語法意思嗎 new BYTE[X*sizeof(DAT)] ----> 比如結果 BYTE[50x10] (DAT*) ------> 強制轉換 (不懂) z=????

(2)有關這一點已經在 (1) 中說明,其實那一行也可以這樣子寫,而且這兩種寫
   法的意義跟結果是一模一樣的 (請你仔細、用心研究),如下:
   pMyStruct=new MYSTRUCT[iX];
   可以這樣子解釋: 為 pMyStruct 宣告一塊記憶體,而這塊記憶體包括 10 個
   MYSTRUCT (陣列),pMyStruct 指向第一個 (index=0) 記憶體位置,所以:
   (a)當這樣寫的時候 pMyStruct[0] 是 access 第 1 個 (index=0) MYSTRUCT
   (b)當這樣寫的時候 pMyStruct[n-1] 是 access 第 n 個 MYSTRUCT
(3)如果以上的解釋方式,還不能夠讓你了解的話,我就再另外舉一個例子,以
   下的兩種寫法 (標示為綠色) 其意義跟結果是一模一樣的       int iY=50;
   int *pi=NULL;
   pi=new int[iY];
//   pi=(int*)new BYTE[iY*sizeof(int)];
   // ...Do something...
   delete pi;       看出來了嗎?? 目前 Win32 的 compiler 對於 int 這個型態的預設佔記憶體
   數都是 4 Bytes,所以當我這樣宣告的時候
   (a)pi=new int[iY]; 總共宣告了 4*50=200 Bytes 給 pi 這個 int 指標
   (b)pi=(int*)new BYTE[iY*sizeof(int)]; 總共宣告了 1*50*4=200 Bytes
      給 pi 這個 int 指標 (經過強制轉型,把 BYTE 指標轉成 int 指標)
z =(DAT*)new BYTE[X*sizeof(DAT)]; //動態配置記憶體指標 ZeroMemory(z,X*sizeof(DAT)); //動態配置的記憶體每個 BYTE 歸零
引言: void __fastcall TForm1::Button1Click(TObject *Sender) { typedef struct{ AnsiString aaa; AnsiString bbb; }DAT; int X=50; DAT *z=NULL; z =(DAT*)new BYTE[X*sizeof(DAT)]; ZeroMemory(z,X*sizeof(DAT)); z[0].aaa="abc"; z[1].aaa="xyz"; z[100].aaa="vvvv"; ----------------------->為什麼可以

(4)為什麼可以?? 不,那當然不可以,而且是很明顯的錯誤,但是 Windows 為
   什麼不會顯示出 Access Violation 的錯誤訊息呢?? 先建議你把以上的程式
   碼改成以下這個樣子執行看看       typedef struct _DAT
   {
      AnsiString aaa;
      AnsiString bbb;
   } DAT;       Memo1->Lines->Clear();
   int X=50;
   DAT *z=NULL;
   z=new DAT[X];
   ZeroMemory(z, X*sizeof(DAT));
   for(int i=0; i<100; i  )
   {
      z[i].aaa=IntToStr(i);
      z[i].bbb=IntToStr(i);
      Memo1->Lines->Add(z[i].aaa ", " z[i].bbb);
   }
   delete z;       當你執行的時候,是不是 Access Violation 馬上跑出來了呢?? 其實原因很
   簡單,這是 Windows 作業系統的「防呆裝置」,也就是說,當發生了很小的
   Access Violation 的時候,Windows 作業系統會概括性承受,尤其是 2000
   以後的作業系統,原本這應該是 M$ 的一番美意,卻害了不少程式設計師,
   以為這樣寫是正確的,但事實卻是相反的,而且有一點要特別注意,那就是
   這樣子寫並不是完全不會出現 Access Violation 的錯誤訊息 (有時候會出
   現,有時候不會出現,造成了程式設計師難抓的大 bug);一旦發生了比較嚴
   重 (大量) 記憶體違規存取的時候,Windows 才會馬上、立即顯示 Access
   Violation 的錯誤訊息,當然,這會導致 Application 被 Windows 作業系
   統強制關閉,所以,要儘量小心避免這種錯誤,當然,最好的方法還是在每
   個函式寫好之後,記得要做「迴圈」及「多執行緒」測試,才能夠找出這些
   潛在且致命的程式碼。有的時候,我們常聽到某些已經出貨 (上線) 的系統
   不太穩定 (有的時候會掛點),其實部分的原因,都是上述的情況所造成的
ShowMessage(z[100].aaa); delete z; } 這樣也可以 這樣就不可以 delete [] z;
-- Enjoy Researching & Developing -- 發表人 - RaynorPao 於 2003/10/27 21:13:24
------
-- 若您已經得到滿意的答覆,請適時結案!! --
-- 欲知前世因,今生受者是;欲知來世果,今生做者是 --
-- 一切有為法,如夢幻泡影,如露亦如電,應作如是觀 --
renth555
一般會員


發表:32
回覆:65
積分:19
註冊:2003-02-17

發送簡訊給我
#8 引用回覆 回覆 發表時間:2003-10-28 20:18:34 IP:61.56.xxx.xxx 未訂閱
謝謝 taishyang 提醒 感謝 RaynorPao 的教導 這種看不到模不著的程式還真的是需要有位老師教導才行 謝謝
tomlee
一般會員


發表:5
回覆:14
積分:18
註冊:2003-10-11

發送簡訊給我
#9 引用回覆 回覆 發表時間:2003-10-30 03:57:47 IP:218.167.xxx.xxx 未訂閱
引言:
引言: typedef struct{ AnsiString GSET; AnsiString NAME; }DAT; int X=50; DAT AAA[X]; 我的問題在於 [X] 因我還不知結構確定值 要程式跑後才知 X=多少 請問這樣的方法有解嗎
renth555 你好: 請參考以下的做法 < class="code"> #include "StrUtils.hpp" // 宣告 struct (建議儘量別使用 AnsiString 宣告在 struct 裡面,在某些應 // 用的情況之下會有問題的;建議改用宣告佔有實體記憶體的 char array) typedef struct _MYSTRUCT { char szGSET[64]; char szNAME[64]; } MYSTRUCT; // 假設已經動態取得 iX=50 int iX=50; // 宣告 MYSTRUCT 的指標 MYSTRUCT *pMyStruct=NULL; // 動態配置記憶體給 MYSTRUCT 的指標 pMyStruct=(MYSTRUCT*)new BYTE[iX*sizeof(MYSTRUCT)]; // 養成好習慣,先將動態配置的記憶體每個 BYTE 歸零 ZeroMemory(pMyStruct, iX*sizeof(MYSTRUCT)); // 釋放記憶體 delete pMyStruct; -- Enjoy Researching & Developing --
    關於動態配置的問題,C   的標準作法應該是這樣:    class DATA
{
   AnsiString GSET;
   AnsiString NAME;
};    DATA *Data = new DATA[ix];
//...
delete [] Data;    或者用標準函式庫中的 vector 來作:    vector Data;    // 執行期可以動態設定大小:
Data.reset(ix);    // 或者一個一個加進去:
for (int i=0; i     
        
系統時間:2024-09-19 11:23:28
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!