找回密碼 或 安全提問
 註冊
|註冊|登錄

伊莉討論區

搜索
發表文章前請先閱讀相關版規尊貴會員無限使用任何功能安全提問(回答) 和 永久尊貴會員 事宜
mg刀劍神域三上悠亜三上上原亞衣惡靈古堡國中
生存遊戲love sealoop trabjvenusblosuccubuslooptrai

休閒聊天興趣交流學術文化旅遊交流飲食交流家庭事務PC GAMETV GAME
熱門線上其他線上感情感性寵物交流家族門派動漫交流貼圖分享BL/GL
音樂世界影視娛樂女性頻道潮流資訊BT下載區GB下載區下載分享短片
電腦資訊數碼產品手機交流交易廣場網站事務長篇小說體育運動時事經濟
上班一族博彩娛樂

文化大革命 紀實錄像

[繁]魔王學院的不適任

中和廣福路 不滿轎車

(4月新番)[繁]轉生貴

[繁]我的英雄學院 Mem

[繁中]霹靂英雄戰紀之
C & C++ 語言C# 語言Visual Basic 語言PHP 語言JAVA 語言
查看: 9296|回復: 14
打印上一主題下一主題

[討論]陣列配置方式 - 靜態、動態、VLA[複製鏈接]

Rank: 5Rank: 5Rank: 5Rank: 5Rank: 5

帖子
2979
積分
12825 點
潛水值
41478 米
跳轉到指定樓層
樓主
發表於 2011-8-2 04:09 PM|只看該作者|倒序瀏覽
可變長度陣列 (Variable Length Array, VLA) 記得之前在各帖中都有討論過,
但突然要找又找不到,特發此帖一次討論完。
以下敘述,避開 scope 問題,若內容有誤,請不吝指正。

-------------
1. 靜態陣列 (Static Array)

早期接觸陣列時,都是給一定的陣列大小,如
  1.     int arr[5];
複製代碼


或是設初始值,讓 compiler 在編譯時計算其大小,如

  1.     int arr[] = {0,0,0,0,0};
複製代碼


若要把元素個數定義成一 macro 也行

  1.     #define N 5
  2.     int arr[N];
複製代碼


甚至用 const 方式定義元素個數也可

  1.     const int N = 5
  2.     int arr[N];
複製代碼


上面這四種方式,包含 define 、 const ,
這些都在編譯期 (compile time) 時完成的事情,
( const 和 編譯期 要解說的話會複雜一點,此處避開不談 )
只要是在「編譯期」就可確定陣列大小的,這裡都叫 Static Array。

------------------

2. 動態陣列 (Dynamic Array)

動態陣列具一特性:無時無刻都可以改變陣列的大小。
意思是你可以突然使陣列變大,也可以突然讓它變小,甚至完全不用它。
在 C/C++ 中,常用 malloc / new 方式進行,如

  1.     /* in C language */
  2.     int N, *x;
  3.     scanf("%d", &N);
  4.     x = (int*)malloc(sizeof(int) * N);
  5.     /* do something */
  6.     free(x);
複製代碼




  1.     /* in C++ language */
  2.     int N, *x;
  3.     cin >> N;
  4.     x = new int[N];
  5.     /* do something */
  6.     delete [] x;
複製代碼


在 C99 標準公佈之前,
只要陣列的元素個數,是在程式執行的時候 (Run time, 執行期) 才決定的,
那就一定要用 Dynamic Array 方式配置記憶體空間,
上述的二段程式碼,N 都是在執行期時,由使用者輸入決定的 (由運算得到也一樣),
故必須使用 Dynamic Array 方式。
Dynamic Array 也可配置多維陣列,此處不予以多談。

副帶一題,真正的「動態」,
我認為可能是 C 語言的 malloc + remalloc 稱之較為合適。

---------------------

3. Static Array / Dynamic Array 差異

第一點差異已由上面提出來了,
static array 是在 compile time 決定元素個數;
dynamic array 是在 run time 決定元素個數。

第二個差異,
dynamic array 不論在配置、釋放記憶體時,
花費時間會較長,故程式中若有一段不停地進行配置、釋放動作,
這時可能要用一點技巧去減少配置、釋放所花費之時間。

第三個差異,
dynamic array 實際上是在 heap 上做配置;
static array 實際上是在 stack 上做配置。
heap 上可實用的記憶體大小,乃依作業系統有所差異,
在 XP 系統中,單一程式最多可使用記憶體為 2G/3G (依版本有所不同),
而 stack 卻遠遠比這數值還小。

看下面例子
  1. #include <iostream>
  2. using namespace std;
  3. #define N 1000000
  4. int main()
  5. {
  6.      int i, sum;
  7.      int x[N];
  8.      for(i=0; i!=N; ++i) x[i]=i;
  9.      for(i=0; i!=N; ++i) sum+=x[i];
  10.      cout << "sum=" << sum << '\n';
  11.      return 0;
  12. }
複製代碼


這段碼不論在 dev-c 或 vc 下,都會失敗,它用的只是普通的 static array,
其中 x 只配置了約 4MB 之記憶體大小,程式就跑不過去了,
可知 stack 裡面可用之記憶體大小真的不大,
但這處確實可藉由 compiler IDE 協助,去調整 stack 最大之大小,
即使可以這麼做,但還是不建議這麼做,
你可以想像,一份不是很大的專案,程式一開起來就吃了五、六百MB,
客戶應都會有所抱怨。
這段碼若改成 Dynamic 的話便可正常執行

  1. #include <iostream>
  2. using namespace std;
  3. #define N 1000000
  4. int main()
  5. {
  6.      int i, sum;
  7.      int *x = new int[N];
  8.      for(i=0; i!=N; ++i) x[i]=i;
  9.      for(i=0; i!=N; ++i) sum+=x[i];
  10.      cout << "sum=" << sum << '\n';
  11.      delete [] x;
  12.      return 0;
  13. }
複製代碼


用動態方式,只是 4MB,差 XP 上限 2GB/3GB 還少很多。
sum 結果是錯的我知道,這麼做是為了避免 compiler 太過於精,
連配置記憶體都不配置。
如果程式碼變下面這樣的話..

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.      int i, sum;
  6.      unsigned N=(unsigned)(0-1);
  7.      int *x = new int[N];
  8.      for(i=0; i!=N; ++i) x[i]=i;
  9.      for(i=0; i!=N; ++i) sum+=x[i];
  10.      cout << "sum=" << sum << '\n';
  11.      delete [] x;
  12.      return 0;
  13. }
複製代碼


裡面大概是要配 4*4G = 16GB 記憶體,這超過 xp 上限太多了,
若真遇到這種問題,大概只有下列幾種方式可解決
a. 換作業系統、加硬體。
b. 換演算法。
c. 將 x 陣列內容寫入檔案裡面去,再做讀取
d. 一台電腦沒 16G,8台電腦就有;8台電腦沒有16G,16台電腦總有吧!
   ( Distrubite Processing System )


-----------

4. 可變長度陣列 (Variable Length Array)

這是在 C99 以後才有的。
也由於 C99 以後才規定,你可以使用這種寫法
  1.      int n=10;
  2.      int x[n] = {0};
複製代碼


早期在 C99 出現時,這都是被禁止的。但 VLA 的出現卻引出來一些爭議,
特別我也是不建議用 VLA 的一群。為何?
再測以下程式碼

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.      int N=1000000;
  6.      int i, sum;
  7.      int x[N];
  8.      for(i=0; i!=N; ++i) x[i]=i;
  9.      for(i=0; i!=N; ++i) sum+=x[i];
  10.      cout << "sum=" << sum << '\n';
  11.      delete [] x;
  12.      return 0;
  13. }
複製代碼


雖只有 4MB 記憶體大小,但很遺憾的, VLA 沒辦法配置出來。
我沒確切的資料能說明,VLA 實際上是在 heap 或是 stack 上,
但我的確相信, VLA 是配置在 stack 上而非 heap,
上面程式只是一個推斷的例子而已。

同時 VLA 我認為它的名稱真的取得不是很好 - 可變長度陣列,
但一旦我用了 int x[N] 時,在 x 生命週期結束之前,
它所有可用元素都只有 N 個,沒辦法變大,沒辦法變小,
我認為直接稱它 semi-dynamic array (半動態陣列) 可能還比較合適。

---------------

5. Variable Legnth Array / Dynamic Array

若拿動態陣列與 VLA 做比較,大致上有幾點是可注意的

a. VLA 可宣告的範圍與 Static Array 無二異,甚至會少一點,
   ( 有另一說,VLA 會配置比實際用得元素還多,但那些多配置的就浪費了。)
   
b. 都是 run time 時配置

c. 並非所有 compiler 都支援 VLA,但所有 compiler 都支援 Dynamic Array

d. Dynamic Array 在配置、釋放時花時間,VLA、Static Array 無此問題。

光是 a. 與 c. ,我便主張不用 VLA,Dynamic Array 在 d. 缺點上之表現,
實際上仍有些技巧可改善一直重覆配置的問題,於此便不多談。

---------------

以上若有誤,歡迎不吝指正。...
瀏覽完整內容,請先 註冊登入會員
分享分享0收藏收藏2支持支持0
如果我說,灌了二頁的水是因為lag / 系統不穩,
我想應該也不會有人相信吧..
分享使你變得更實在,可以使其他人感到快樂,分享是我們的動力。今天就來分享你的資訊、圖片或檔案吧。

使用道具檢舉

xxxx9659 該用戶已被刪除
頭香
發表於 2012-3-8 03:09 PM|只看該作者
回覆中加入附件並不會使你增加積分,請使用主題方式發佈附件。
之前對VLA的概念很朦朧 這篇寫得好詳細!
成為伊莉的版主,你將獲得更高級和無限的權限。把你感興趣的版面一步步地發展和豐盛,那種滿足感等著你來嚐嚐喔。

使用道具檢舉

Rank: 3Rank: 3Rank: 3

帖子
1149
積分
2250 點
潛水值
36043 米
3
發表於 2012-3-10 08:47 PM|只看該作者
回覆中加入附件並不會使你增加積分,請使用主題方式發佈附件。

使用道具檢舉

Rank: 3Rank: 3Rank: 3

帖子
1615
積分
1865 點
潛水值
30770 米
4
發表於 2012-3-16 03:23 PM|只看該作者
i think VLA like dynamic , complier gen array size from compile time.
can do this  ?  void f(n) { char x[n]; }
如果你忘記伊莉的密碼,請在登入時按右邊出現的 '找回密碼'。輸入相關資料後送出,系統就會把密碼寄到你的E-Mail。

使用道具檢舉

Rank: 2Rank: 2

帖子
184
積分
606 點
潛水值
10574 米
5
發表於 2012-3-16 09:42 PM|只看該作者
所有積分大於負-100的壞孩子,將可獲得重新機會成為懲罰生,權限跟幼兒生一樣。
superjoeliao 發表於 2012-3-10 08:47 PM
下載: 訪客無法瀏覽下載點,請先 註冊登入會員

受教了
寫得真好
可否再介紹2維的Dynamic Array
  1. int num,x**;
  2. scanf("%d",&num);

  3. x=(int **)malloc(num*sizeof(int *));
  4. for(int y=0;y<num;y++){
  5.     x[y]=(int*)malloc(num*sizeof(int*));
  6. }
複製代碼
...
瀏覽完整內容,請先 註冊登入會員





所有積分大於負-100的壞孩子,將可獲得重新機會成為懲罰生,權限跟幼兒生一樣。

使用道具檢舉

Rank: 3Rank: 3Rank: 3

帖子
1149
積分
2250 點
潛水值
36043 米
6
發表於 2012-3-16 10:20 PM|只看該作者
感謝指教
那再請教 2維的釋放記憶體的程式要如何實現呢
還請賜教
若新密碼無法使用,可能是數據未更新。請使用舊密碼看看。

使用道具檢舉

帖子
0
積分
0 點
潛水值
20 米
7
發表於 2012-3-17 02:37 AM|只看該作者
若有安裝色情守門員,可用無界、自由門等軟件瀏覽伊莉。或使用以下網址瀏覽伊莉: http://www.eyny.com:81/index.php
很棒 現在對VLA 動態陣列, 靜態陣列都有更深一步的認知了.
分享使你變得更實在,可以使其他人感到快樂,分享是我們的動力。今天就來分享你的資訊、圖片或檔案吧。

使用道具檢舉

Rank: 2Rank: 2

帖子
219
積分
760 點
潛水值
9464 米
8
發表於 2012-3-17 07:29 AM|只看該作者
若有安裝色情守門員,可用無界、自由門等軟件瀏覽伊莉。或使用以下網址瀏覽伊莉: http://www.eyny.com:81/index.php
superjoeliao 發表於 2012-3-16 10:20 PM
下載: 訪客無法瀏覽下載點,請先 註冊登入會員

感謝指教
那再請教 2維的釋放記憶體的程式要如何實現呢
還請賜教
  1. for(int i = 0; i < num; i++) {
  2.     free(x[i]);
  3. }
  4. free(x);
複製代碼
...
瀏覽完整內容,請先 註冊登入會員

使用道具檢舉

Rank: 3Rank: 3Rank: 3

帖子
1149
積分
2250 點
潛水值
36043 米
9
發表於 2012-3-17 04:07 PM|只看該作者
若有安裝色情守門員,可用無界、自由門等軟件瀏覽伊莉。或使用以下網址瀏覽伊莉: http://www.eyny.com:81/index.php
感謝指導
如此一來這就是一篇
很完整的c語言Dynamic Array

趕緊抓下珍藏
成為伊莉的版主,你將獲得更高級和無限的權限。把你感興趣的版面一步步地發展和豐盛,那種滿足感等著你來嚐嚐喔。

使用道具檢舉

Rank: 3Rank: 3Rank: 3

帖子
328
積分
2651 點
潛水值
10849 米
10
發表於 2012-3-23 01:22 AM|只看該作者
如果你忘記伊莉的密碼,請在登入時按右邊出現的 '找回密碼'。輸入相關資料後送出,系統就會把密碼寄到你的E-Mail。
本帖最後由 EdisonX 於 2012-4-5 03:16 AM 編輯
p12332145600 發表於 2012-3-16 09:42 PM
下載: 訪客無法瀏覽下載點,請先 註冊登入會員

二維配置不建議這麼做,原因在於碎片化問題,
沒辦法調用 memset、memcpy 等 function,
...
瀏覽完整內容,請先 註冊登入會員





如果沒有明天
我想見你最後一面
若對尊貴或贊助會員有任何疑問,歡迎向我們查詢。我們的即時通或MSN: admin@eyny.com

使用道具檢舉

Rank: 3Rank: 3Rank: 3

帖子
328
積分
2651 點
潛水值
10849 米
11
發表於 2012-3-23 01:29 AM|只看該作者
如果瀏覽伊莉時速度太慢或無法連接,可以使用其他分流瀏覽伊莉,www01.eyny.com(02,03)。
hkaa88 發表於 2012-3-16 03:23 PM
下載: 訪客無法瀏覽下載點,請先 註冊登入會員

i think VLA like dynamic , complier gen array size from compile time.
can do this  ?  void f(n) { ch ...

no, this article means dynamic array , allocate memory on heaps.
...
瀏覽完整內容,請先 註冊登入會員
如果沒有明天
我想見你最後一面

使用道具檢舉

zz186980 該用戶已被刪除
12
發表於 2012-4-4 08:53 AM|只看該作者
若對尊貴或贊助會員有任何疑問,歡迎向我們查詢。我們的即時通或MSN: admin@eyny.com
果真是精華中的精華,了解不少!!!
如果發覺自己無法使用一些功能或出現問題,請按重新整理一次,並待所有網頁內容完全載入後5秒才進行操作。

使用道具檢舉

gerry0622 該用戶已被刪除
13
發表於 2012-4-4 11:43 AM|只看該作者
所有積分大於負-100的壞孩子,將可獲得重新機會成為懲罰生,權限跟幼兒生一樣。
本帖最後由 gerry0622 於 2012-4-4 11:51 AM 編輯

10樓的作法真的很不錯耶,把二維陣列配置用一維去模擬,
而且操作和釋放上也十分方便!不過第18行應該是 free(*arr), free(arr);不然好像怪怪的。

點評

EdisonX 更誤一下,18行應該是 free(arr); free(*arr) ; 沒錯。 另有其他配置方式 void** p = (sizeof(void*) * H + SizeOfEle * H * W); free 時只需做 free(arr) 一次即可。  發表於 2012-4-5 03:17 AM
EdisonX 18行應該是 free(arr); free(*arr) 的話會出包 (前面的 pointer都不會釋放到), 謝謝指出。  發表於 2012-4-5 03:15 AM

使用道具檢舉

Rank: 2Rank: 2

帖子
157
積分
435 點
潛水值
8233 米
14
發表於 2012-5-15 04:40 PM|只看該作者
分享使你變得更實在,可以使其他人感到快樂,分享是我們的動力。今天就來分享你的資訊、圖片或檔案吧。
^_^學習了,感謝分享!

使用道具檢舉

Rank: 4Rank: 4Rank: 4Rank: 4

帖子
7565
積分
4321 點
潛水值
34960 米
15
發表於 2012-5-19 02:19 AM|只看該作者
若有安裝色情守門員,可用無界、自由門等軟件瀏覽伊莉。或使用以下網址瀏覽伊莉: http://www.eyny.com:81/index.php
動態記憶體配置的迷思很多
很多的人不是那麼清楚
我必須要在這個地方提出一點基本的建議
在32位元的系統裏
有alignment上的問題
意思就是說 即使配置1個byte的記憶體時 事實上系統是保留了2個word給你
在64位元的系統裏
即使配置1個byte的記憶體 事實上系統仍然是保留了4個word給你
但是
不要以為多配置給你就可以使用
那是很容易出錯的
...
瀏覽完整內容,請先 註冊登入會員





系統已重置禁訪用戶到普通用戶和密碼一次

使用道具檢舉

您需要登錄後才可以回帖 登錄 | 註冊

Powered by Discuz!

© Comsenz Inc.

重要聲明:本討論區是以即時上載留言的方式運作,對所有留言的真實性、完整性及立場等,不負任何法律責任。而一切留言之言論只代表留言者個人意見,並非本網站之立場,用戶不應信賴內容,並應自行判斷內容之真實性。於有關情形下,用戶應尋求專業意見(如涉及醫療、法律或投資等問題)。 由於本討論區受到「即時上載留言」運作方式所規限,故不能完全監察所有留言,若讀者發現有留言出現問題,請聯絡我們。有權刪除任何留言及拒絕任何人士上載留言,同時亦有不刪除留言的權利。切勿上傳和撰寫 侵犯版權(未經授權)、粗言穢語、誹謗、渲染色情暴力或人身攻擊的言論,敬請自律。本網站保留一切法律權利。
回頂部