1. 程式人生 > >如何在C++中動態分配二維陣列

如何在C++中動態分配二維陣列

這個問題應該是我以前在CSDN蹭分時回答次數比較多的一個問題了,我的回答一般是三種方法:(1)用vector的vector,(2)先分配一個指標 陣列,然後讓裡面每一個指標再指向一個數組,這個做法的好處是訪問陣列元素時比較直觀,可以用a[x][y]這樣的寫法,缺點是它相當於C#中的一個鋸齒 陣列,記憶體空間不連續。(3)直接分配一個x*y大小的一維陣列,這樣保證空間是連續的,但訪問陣列元素不直觀。對於我這個“經典”回答,我那時還一直是 挺得意的,至少從蹭分的角度來看,這樣回答還是很有效的。

  今天在ChinaUnix論壇閒逛時看到一個貼子,再次證明了我在C++方面才疏學淺。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void **darray_new(int row, int col, int size)
{
void **arr;

arr = (void **) malloc(sizeof(void *) * row + size * row * col);
if (arr != NULL)
{
void *head;

head = (void *) arr + sizeof(void *) * row;
memset(arr, 0, sizeof(void *) * row + size * row * col);
while (row--)
arr[row] = head + size * row * col;
}
return arr;
}

void darray_free(void **arr)
{
if (arr != NULL)
free(arr);
}
嗯,連續分配記憶體,而且可以用a[x][y]的方式來訪問!可謂二維陣列動態分配的絕妙方法!這段程式是C的,似乎要改成支援物件分配的C++版也不是什麼難事(不過估計得用上placement new吧,嗯,需要再思考一下……)。

2007-06-13 12:38 補充:

  經過試驗,C++版出爐了:)關鍵點還是在於placement new和顯示的解構函式呼叫,用於保證物件可以正常的構造和析構。
  這個實現也還是有不少缺點的,比如,陣列的大小必須記住,才能保證析構所有物件。不過這點可以通過改進分配方法演算法,把陣列大小也用一點空間儲存起來。
  另一個缺點是,從語法上看,很容易讓人誤把darray_new返回的指標以為是資料區的起始地址,從而可能導致一些邏輯錯誤。

#include <iostream>
#include <cstdlib>
#include <new>

template <typename T>

T **darray_new(int row, int col)
{
    int size = sizeof(T);
    void **arr = (void **) malloc(sizeof(void *) * row + size * row * col);
    if (arr != NULL)
    {
        unsigned char * head;
        head = (unsigned char *) arr + sizeof(void *) * row;
        for (int i = 0; i < row; ++i)
        {
            arr[i] =  head + size * i * col;

            for (int j = 0; j < col; ++j)
                new (head + size * (i * col + j)) T;
        }
    }
    return (T**) arr;
}

template <typename T>
void darray_free(T **arr, int row, int col)
{
    for (int i = 0; i < row; ++i)
        for (int j = 0; j < col; ++j)
            arr[i][j].~T();
    if (arr != NULL)
        free((void **)arr);
}

2007-06-13 21:00補充
本文僅為技術層面的討論,實踐中考慮用
boost::multi_array之類的現成的解決方案可能會更有效。