Wednesday, September 13, 2006

動態宣告二維陣列

寫程式時, 『變數宣告』指的是請作業系統分配 (allocate) 一塊大小合適的記憶體, 讓我們作為儲存資料之用。因此, 我們必須告訴作業系統, 我們要儲存的資料是什麼型態, 然後, 根據程式設計師所提供的變數型態, 作業系統就會知道該分配多大的記憶體給我們使用。因此, 變數宣告通常會寫在程式的最前面, 希望程式一開始執行時, 就把需要用到的記憶體通通分配好。

標題中『動態宣告』指的是當程式設計師在寫程式時, 並無法確實知道程式在執行時需要用的多大的記憶體, 必須等到程式真正執行時(run time), 才會知道確實的大小。為了解決這樣的問題, 就必須允許程式設計師在執行程式時, 才臨時去宣告, 要求分配記憶體, 這就是『動態』兩個字的意義由來。

用二維陣列來儲存數位影像是非常直覺的想法, 不過, 需要用動態宣告方式的原因則是因為我們不知道要事先宣告一個多大的二維陣列才夠儲存你所開啟的影像。這邊就是要介紹 BCB 中, 要動態宣告一個二維陣列的作法。

#include <iostream.h>
// 注意: 必須加入這一行到程式最前面, 否則我們後面用到的 std::bad_alloc 會沒有定義

unsigned char **ucMatrix;
/* 說明:
1. ucMatrix 就是我們要宣告的二維陣列的名稱, 為了讓我們在寫程式時, 一看到這個名稱就知道其資料型態為何, 我們在名稱之前加入了小寫的 uc, 代表 unsigned char 的縮寫,
2. 這邊用 unsigned char 當例子的原因是影像的色彩值範圍為 0 ~ 255, 剛好就是 unsigned char 可以表示的數值範圍。
3. 名稱之前, 我們放了兩個 star 符號 ( ** ), 就是要告訴 BCB 的編譯器, 這個名稱本身是一個指到二維陣列的名稱。
結束說明 */

int iImageHeight=0, iImageWidth=0;

// 說明: 這兩個變數是用來儲存影像 ( image ) 的高 ( height ) 與寬 ( width ) 的, 至於變數名稱最前面的小寫 i, 也是用來指出其資料型態為 int

 try
  {
  ucMatrix = new unsigned char *[iImageHeight];
  for (j=0;j<iImageHeight;j++)
   ucMatrix[j] = new unsigned char [iImageWidth];
  }
 catch (std::bad_alloc)
  {
  ShowMessage("Could not allocate memory...Bye");
  exit(-1);
  }
 
/* 說明:
1. 如果有一段程式 ( 用大括號 {}, 括起來) 有可能發生一些特殊例外的情況, 以上面的例子來說, 要求系統給予一塊記憶體, 在一般情況下, 這段程式可以順利要到記憶體繼續執行; 可是, 當系統已經沒有多餘的記憶體分配給你的時候, 程式該怎麼辦呢? 這種情況就是可能發生的例外情況。在 C++ (BCB) 中, 你可以將這段程式碼的前面加上 try 這個 keyword, 讓系統知道可能會發生例外情況, 需要例外處理程序支援。
2. 至於不同的例外情況, 要做不同的例外處理, 我們必須用 catch 這個 keyword 來加以分別。以我們的例子來說, 當發生了 std::bad_alloc 這種情況時, 請秀出 "Could not allocate memory... Bye" 字串, 然後程式結束 exit(-1);
3. new 就是提供動態記憶體配置 (dynamic storage allocation) 的指令。如果成功配置到記憶體, new 這個 operator 就會傳回一個指標 (pointer), 指向所配置到的記憶體位置。如果失敗了, new operator 就會呼叫 new_handler 函數。這個函數內定的處理方式就是指出發生了一個 bad_alloc 的例外情況。然後再由程式設計師透過例外處理指令 catch 來接手該如何處理這個例外情況。
4. 由於我們要宣告的是一個二維陣列, 因此整個步驟分成兩部份, 首先要求配置 iImageHeight 個一維陣列的指標, 每一個指標都是指向一個資料型態為 unsigned char 的變數。如果成功了, 就將這個陣列的指標存到 ucMatrix 這個變數中。接著, 再利用for 迴圈要求 iImageHeight 個陣列, 每個陣列都有 iImageWidth 個元素 (elements), 每一個元素的資料型態都是 unsigned char。
結束說明 */

注意: 上述程式為了程式的可讀性, 用了全型的空白" "來控制部落格文章的內縮顯示。因此, 如果你要直接複製上述程式到 C++ Builder 執行, 請務必將全型空白" "改成半型空白" ", 否則, 編譯時發出現以下的錯誤訊息。:
[C++ Error] Unit1.cpp(40): E2206 Illegal character ' ' (0xa140)

No comments:

Post a Comment