c++的new操作符是該語言乙個非常好的語法特性,然而實際使用中卻發現new操作符有不少限制,為突出的一點便是用new操作符分配多維陣列空間時,不能讓陣列的每一維都動態可變。本文將對此提出乙個簡單直觀的解決方案,在乙個實際問題的簡化模型中加以說明,並以此釋清許多初學者對c++中new操作符與多維陣列的誤區。
1. 問題的提出--多維可變陣列的實際用途
下面是實際程式設計中遇到問題的乙個簡化模型。chessboard是乙個棋盤類,其中的m_board是用來儲存棋盤上棋子資訊的二維陣列。dimension是棋盤的尺寸或者維數,因為要用於陣列宣告,所以它必須是乙個編譯期間可以確定其值的常量,這裡我們使用了無名列舉。對於不同種類棋的棋盤大小是不同的,對於黑白棋,dimension定義為8,對於五子棋,dimension應該為15,而圍棋呢,又得是19。對此這段**採用了條件編譯來確定dimension常量的值,以保證這段**具有較好的可重用性。
由於m_board必須是編譯期常量,於是在程式執行時刻m_board陣列的大小是不可改變的。如果程式中要同時實現黑白棋、五子棋和圍棋就不能這樣來做了--當然這樣有點誇張,不過就算光是圍棋也有9x9、13x13、19x19幾種棋盤,而且應當能讓使用者在程式執行時自由選擇。
class chessboard
; int m_board[dimension][dimension];
public:
/*其它成員函式
......
*/}
對此我們必須用new操作符或者malloc函式在程式執行時刻為m_board動態分配空間,由於new支援更多的c++特性,因此我們的程式採用了new操作符。
2. msdn中用new申請多維陣列的說明--進一步認識new操作符
下面的**摘自msdn中的「new operator」,其中第二行在vc6.0中編譯將得到乙個錯誤資訊,對此msdn中的說明是new操作符返回的型別為float(*)[25][10],即指向float[25][10]的指標(去掉最左邊的一維)。正確**應當如3、4行所示。
1. float *fp;
2. fp = new float[10][25][10]; //錯誤資訊:cannot convert from 'float (*)[25][10]' to 'float *'
3. float (*cp)[25][10];
4. cp = new float[10][25][10];
int (*m_board)[dimension]; //在類的成員變數中宣告
m_board = new int[changeable][dimension]; //根據使用者選擇來確定相應的changeable值
不難看出,由於仍然必須用編譯期常量dimension來宣告陣列,所以m_board陣列只能有一維可變,這種方法對我們的問題是毫無用處的。
3.解決方案
這裡給出兩種解決方案,並對第二種方案給出具體**。
1). 我們可以申請大小為xsize*ysize的一維陣列,然後自己通過對xy下標換算來定位相應的儲存單元,**如下:
int *p=new int[ysize*xsize]; file://xsize和ysize應該定義為常量
file://但是對於p[y][x]的引用便成了語法錯誤,應該為
p[y*xsize + x]=y*1000 + x;
這種方法最大的好處是陣列維數可以自由確定,甚至可以動態確定,因為都是轉換為一維陣列。但是它的最大的不便之處就是下標轉換的繁瑣,在多維陣列的情況下更為明顯。如下面這段**是一段檢驗下標轉換是否正確的程式,其輸出結果應該為每個陣列單元的位址都不相同,而且都落在「開始位址」和「結束位址」之間。
const int ysize=6;
const int xsize=7;
const int zsize=9;
int *p=new int[ ysize*xsize*zsize ];
file://但是對於p[y][x]的引用便成了語法錯誤,應該為
cout << (int)p << "開始位址\n";
cout << ((int)p)+sizeof(int)*ysize*xsize*zsize << "結束位址\n";
for(int z=0;z<zsize;z++)
}}
可以看到其中的陣列p僅僅是乙個三維陣列的但是其下標轉換z*ysize*xsize+y*xsize+x已經相當繁瑣了,使用上的繁瑣常常會成為程式中bug的**。因此這種方法對初學者並不適用,但它的靈活性與簡單性使我們不能忽視它。利用這種方法可以將多維陣列封裝成乙個通用類,不但可以動態改變陣列每一維的大小,而且連陣列的維數都可以動態改變(這個通用陣列類正在筆者的計畫之中)。
2). 將多維陣列當作多個一維陣列。
這裡我們直接給出前面提出棋盤類問題的**,建構函式chessboard、析構函式~chessboard和輸出函式output中分別對應給出了二維陣列m_board的空間分配,空間釋放和單元引用的相關**。而且可以看出雖然這種方法需要用迴圈來分配、釋放空間並且需要額外的儲存空間,但從output函式可以看到,它的使用與常規陣列使用的語法是一致的,較上面的第一種方法繁瑣的下標轉換要方便得多。
由於**並不複雜,除了**中的注釋外,就不再另外詳細說明。雖然這裡給出的是二維陣列,但也不難將其擴充到多維陣列。
class chessboard;
chessboard::chessboard(int boardsize=8):
dimension(boardsize)
} }
chessboard::~chessboard()
delete m_board;
} void chessboard::output()}}
}
c 動態陣列的使用
在c 中,有的時候會遇到變長的陣列 不管是一維的還是二維的 這個時候就需要用到動態陣列了,並且要用new和delete兩個操作符,這倆操作符一般成對使用。先說一維的動態陣列吧,直接上 1 include2 using namespace std 3int main 4用完了以後,在14行釋放掉了這個...
五 C 中CArray動態陣列的使用
carray 是乙個可以存放任何資料型別的複雜的陣列結構,並可以實現陣列的動態管理,在記憶體中的位址分配是連續的,可以提高程式的效率。在 mfc中還提供了常用的變數型別,分別定義為 cbytearray cwordarray cuintarray cdwrodarray cstringarray c...
C 中動態陣列 陣列引數
一 c 中的動態陣列 寫程式的時候,我在想動態陣列怎麼寫,new int,方括號中可以寫常量嗎,真是鬱悶,一些基本的知識都不記得,還是多練練吧。int pia new int 10 陣列的維數可以是任意的複雜表示式。delete pia 動態分配陣列時,陣列元素為類型別呼叫預設建構函式,內建型別的不...