討論區快速選單
知識庫快速選單
程式設計俱樂部Facebook粉絲團 掌握Salesforce雲端管理秘訣
[ 回上頁 ] [ 討論區發言規則 ]
動態配置2維陣列與realloc的問題....
更改我的閱讀文章字型大小
作者 : ychch0819(ychch) 人氣指數超過10000點
[ 貼文 60 | 人氣 11665 | 評價 30 | 評價/貼文 0.5 | 送出評價 9 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/7 下午 01:26:14
請問各位高手一個問題…

我在程式中要動態配置一個2維陣列(第二維固定為1024),且程式中可能需要realloc第一維…

因此我在一開始的程式中,用calloc建立了一個2維空間…
程式如下:

save=(char**)calloc(MaxSize, sizeof(char*));
for (i=0;i<MaxSize;i++)
{
    save[i]=(char*)calloc(1024,sizeof(char));
}

之後,我之前定義的MaxSize不夠用,因此我想放用realloc放大…
因為用realloc後的指標可能會改變…因此我想請問第一維用realloc放大後,本來第二維的指標需要做處理嗎!?

我的程式如下:
save=(char**)realloc(save,sizeof(char*)*MaxSize*multiple);

感謝…
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人ychch0819註記此篇回應為最佳解答 2009/12/7 下午 11:07:12
>我在程式中要動態配置一個2維陣列(第二維固定為1024),且程式中可能需要realloc第一維…

嚴格來說, C 及 C++ 語言本身沒有 2 維陣列, 所有 2 維及以上的陣列實際上是 array of array(s). 只是語法上讓你用起來有 N 維的感覺.

>因此我在一開始的程式中,用calloc建立了一個2維空間…
>程式如下:
>
>save=(char**)calloc(MaxSize, sizeof(char*));

如果是用 C 語言, 不需要 typecast. 如果你是用 C++, 那我建議你用 C++ 的 collection classes 來實施.


>for (i=0;i<MaxSize;i++)
>{
> save[i]=(char*)calloc(1024,sizeof(char));

sizeof(char) 一定是 1, 沒有必要.

>}

比較好的 sizeof 使用方法是儘量用變數, 而不是類型.

  save = calloc(MaxSize, sizeof *save);
  ...
  save[i] = calloc(1024, sizeof **save)

這樣, 當 'save' 改換類型的時候 (比方說改成 wchar_t, 甚至是 struct), 你不需去更改每一個 calloc().

另外, 使用 calloc() 要注意, calloc() 會把配置的記憶體設為 all-bits zero. 但 all-bits zero 並不適合每一個平台及類型, 比方說, 浮點數的 0.0 值未必是 all-bits zero. 在某些平台上, null pointer 的內部代表值也未必是 all-bits zero. 所以 calloc() 最好避免使用.


>之後,我之前定義的MaxSize不夠用,因此我想放用realloc放大…
>因為用realloc後的指標可能會改變…因此我想請問第一維用realloc放大後,本來第二維的指標需要做處理嗎!?

其實, 你上面的程式並沒有建立 2 維空間. 上面所做的是建立 MaxSize + 1 個一維空間:

      char**   char*
      +====+   +====+   +=====..===+
 save | *--+-->| *--+-->| | | .. | |
      +====+   |----|   +=====..===+
               | *--+-+
               |----| |   +====..==+
               :    : +-->| | |..| |
               :    :     +====..==+ 
               |----|
               | *--+-->...
               +====+


每一個 char* 所指向的 char[1024] 是各自獨立的, 每一個 char* 指向的長度可以不同. 所以它們並不是真正的 2 維, 真正的 2 維是這樣子的:

   0        1024
  +=====..===+
  | | | .. | |[0]
  |-----..---|
  | | | .. | |[1]
  |-----..---|
  ∼          ∼
  |-----..---|
  | | | .. | |[MaxSize-1]
  +=====..===+


>我的程式如下:
>save=(char**)realloc(save,sizeof(char*)*MaxSize*multiple);

建議把 sizeof(char*) 改成 sizeof *save.

由於它們不是真正的 2 維, 所以當你增長「第一維」時, 如果需要從新配置並複製, realloc() 所做的類似這樣:
    char **temp = malloc(newsize * sizeof *save);
    for (i = 0; i < oldsize; ++i)
    {
      temp[i] = save[i];
    }
    free(save);
    save = temp;


所複製的是 char* 陣列堛澈標, 原來的「第二維」不會有影響.

作者 : kenneth_deng(Kenneth_Deng)
[ 貼文 12 | 人氣 0 | 評價 0 | 評價/貼文 0 | 送出評價 8 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/21 上午 09:09:51

>嚴格來說, C 及 C++ 語言本身沒有 2 維陣列, 所有 2 維及以上的陣列實際上是 array of array(s). 只是語法上讓你用起來有 N 維的感覺.

>每一個 char* 所指向的 char[1024] 是各自獨立的, 每一個 char* 指向的長度可以不同. 所以它們並不是真正的 2 維, 真正的 2 維是這樣子的:
>
>   0        1024
>  +=====..===+
>  | | | .. | |[0]
>  |-----..---|
>  | | | .. | |[1]
>  |-----..---|
>  ∼          ∼
>  |-----..---|
>  | | | .. | |[MaxSize-1]
>  +=====..===+
>
我想請教一下前輩,青衫前輩有提到:
二維以上, int**和int[][]是不同的, 前者是多個記憶體(一維陣列)所組成, 後者是一個記憶體(二維陣列)所組成。
這裡也提到所以有二維陣列都是由一維所組成的,那麼int[][]到底是由一維組成的,還是原生就是二維的
作者 : sleepyfish(愛睏魚) C#優秀好手C++優秀好手貼文超過500則
[ 貼文 524 | 人氣 0 | 評價 2890 | 評價/貼文 5.52 | 送出評價 13 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/21 下午 10:28:51
目前 PC 上的記憶體定址一直都是線性的,所以所謂的“二維”,都是 compiler
幫你規劃好一整塊記憶體,然後計算出每個維度所在的真正線性位址。因此,
若是靜態的陣列,你必須明確地告訴 compiler 你要的 size 才行。

(int **) ........ 稱為 pointer to pointer,中文通常翻譯為“指標的指標”;顧
名思意,它就是一個指標,而其指向的 address,實際上也是一個指標,這個
指標必須要指向一個真正存放 int 的 address 才會有實質上的意義。

因為靜態陣列必須要在 compiler 前就宣告大小,比較沒有彈性,因此,若是
無法確知 size 的範圍,或是真正需要的 size 差距很大時,為了節省記憶體空
間,通常都會在程式中先定義指標,等到 runtime 能確定記憶體需求大小時,
再用 malloc() / calloc() / realloc() 等方式跟系統要適當的記憶體大小。

針對二維陣列的動態宣告,通常都是先宣告一個一維 (int *) [] 陣列,或是用
malloc() 先要一塊連續 (int *) 的位址大小來當作指向第一維的指標,再為第
一維的每個單位用 malloc() 要到其第二維的記憶體空間 ....... 這就是青杉大
所說, int ** 所呈現出的記憶體空間可能是不連續的意思。

P.S: 若是你的二維空間的記憶體使用情況是不規則且差距很大時,用 int **
使用記憶體會比較有效率些,這時你需要自行定義一個 structure 來記憶每個
第一維元素下的第二維大小即可。
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/22 上午 01:55:58
>我想請教一下前輩,青衫前輩有提到:
>二維以上, int**和int[][]是不同的, 前者是多個記憶體(一維陣列)所組成, 後者是一個記憶體(二維陣列)所組成。

前者只是個指標而已. 在配置或設值之前, 它並不指向什麼地方.

而 int[N1][N2] 是定義後就可以存取的一個區塊.

但指標跟陣列是兩個完全不同的東西, 跟維數沒有關係. 這裡有過詳細的討論.

http://www.programmer-club.com.tw/pc2020v5/forum/ShowSameTitleN.asp?board_pc2020=c&id=37623


>這裡也提到所以有二維陣列都是由一維所組成的,那麼int[][]到底是由一維組成的,還是原生就是二維的

嚴格說起來, C 及 C++ 語言本身沒有多維陣列. 所謂的多維陣列, 實際上是一維陣列所構成, 而陣列的每一個元素又是個陣列. 比方說:

  int A[3][4];

'A' 是 3 個一維陣列, 在這個陣列, 每一個元素是個 int[4] 陣列:

      int〔4〕
     +===================+
  A  |  〔0〕 〔1〕 〔2〕 〔3〕  |
     | +---------------+ |
 〔0〕 | |int|int|   |   | |
     | +---------------+ |
     |-------------------|
     | +---------------+ |
 〔1〕 | |   |   |   |   | |
     | +---------------+ |
     |-------------------|
     | +---------------+ |
 〔2〕 | |   |   |   |   | |
     | +---------------+ |
     +===================+


暫時回到一維陣列. 我們知道, 當用在大多數的語句堮, 陣列的名字會轉換成指標, 指向第一個元素. 也就是說, Ary 等於 &Ary[0].

而當我們寫 Ary[n] 的時候, 編譯器會把它轉為 *(Ary + n). 這兩種寫法是一樣的, Ary[n] 是 *(Ary + n) C 語言語法給我們的一個方便.

這是一維陣列與指標之間的關係.

同樣的關係也適用在多維陣列. 如果 A 是個 2 維陣列, 那 &A[0] 則指向第一個元素, 既 int[4]. 所以說, C 語言的多維陣列實際上是個 array of arrays.

作者 : kenneth_deng(Kenneth_Deng)
[ 貼文 12 | 人氣 0 | 評價 0 | 評價/貼文 0 | 送出評價 8 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/22 上午 09:26:57
剛看完各位前輩的文章,重新消化了一下,感覺觀念又清晰了不少

並整理了一下:
a[m][n]是由m個一維,每個維度有n個元素所構成的陣列
指標所模擬的方式則是由m+1個一維所構成的陣列
前者是一個"連續"且需事先配置好的記憶體空間;而後者是一個不一定"不連續"且在執行時才配置的記憶體空間
作者 : kenneth_deng(Kenneth_Deng)
[ 貼文 12 | 人氣 0 | 評價 0 | 評價/貼文 0 | 送出評價 8 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/23 上午 10:59:28
>  int A[3][4];

那麼想再請教一下前輩

A[0]=*(A+0)代表第一個ROW的第一個位置
A[1]=*(A+1)代表第二個ROW的第一個位置
A[2]=*(A+2)代表第三個ROW的第一個位置

&A[1]+1=A[2] 這樣的式子成立嗎


 板主 : simula
 > C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
C++
1 Raymond 13050 
2 青衫 4760 
3 simula 4690 
4 coco 4030 
5 白老鼠(Gary) 3670 
6 ozzy 2540 
7 Ben 2250 
8 Anderson 1960 
9 windblown 1650 
10 Kenny 1560 
C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.171875