2013-07-02 11 views
15

これはしばらく私を悩ませました。私は大量のデータを保持するために大きなバッファを作っていることがよくあります。これは、次のデータセットのサイズが変わるたびに動的にバッファを割り当てたり割り当てを解除したりするのを避けるのに役立ちます。1D配列をC++で2D配列としてアクセス

たとえば、実際の有効サイズには大きすぎる配列がありますが、有用なデータの長さはわかります。

int amountOfData = 9; 
char data1D[100] = some data that is only 9 bytes long stored in a 100 byte array 

2次元配列インデックスを使用するこのデータセットで実行したいアルゴリズムがあります。だから私は、次のようにデータにアクセスできるようにする。このため

int xlength = 3; 
int ylength = 3; 

を:

cout << "I am accessing this data as a 2D array: " << data1D[0][1] << endl; 

は、私は2次元配列のxlengthとylengthがあることを行っていることを知っているこのアルゴリズムのために言うことができます反復は、amountOfData = 9です。ただし、長さは次の反復で異なる場合があります。つまり彼らはxlength = 4ylength = 4と与えられるかもしれませんamountOfData = 16

2D配列インデックスを使用して1D配列をキャストできるようにするために、何らかのキャストを行いたいとします。最初の1Dの長さはどれくらいの長さで、私の2D xlengthylengthの長さがわかるので、newまたはmallocを使わずに簡単にできるはずです。最初の100バイトが有効なデータセット私に。

私がいることを実感:コンパイラは二次元のサイズを知らないため

char** data2d = (char**) data1D; 

が動作しません。しかし、私はそれが実行時に何であるか知っている!

これが本来の理由は何ですか? 回避策はありますか? 何も分からないのですか?あなたの行/列の長さを知っている場合

+1

[ベクトル](http://en.cppreference.com/w/cpp/container/vector)を参照してください。 –

+0

どのような種類のデータをdata1Dで使用する予定ですか? – Amadeus

+0

@Tomas Badan私は例として 'char'sを使用しましたが、' unsigned short'の2次元配列として 'unsigned char'sの1D配列にアクセスしたいときに、この問題の特定のケースが発生しました。 1Dアレイは、独自のカメラソフトウェアから吐き出されました。私は結果の画像に2Dピクセルデータとしてアクセスしたいと思います。 – dinkelk

答えて

4

あなたが唯一の実行時に、配列の長さを知ったら、私は2次元配列を使用していないこの問題を解決する方がよいと思いますが、関数を使用して、それをエミュレートします。たとえば、C:

char data1D[1000] = {0}; 

unsigned int getElement(unsigned int x, unsigned int y, 
      unsigned int xMax, unsigned int yMax) 
{ 
    // Do some error tests 
    return ((unsigned int *) data1D)[x*xMax + y]; 
} 
1

(行または主要な柱とないものに応じて)...私は1次元配列としての治療のために... ...それはのようなものだ

char get_value(char *arr, int row_len, int x, int y) { 
    return arr[x * row_len + y]; 
} 

を信じます2D。

2DダイナミックCアレイのもう一つのこと。

char **arr = (char **)malloc(row_size * sizeof(char *)); 
int x; 
for (x = 0; x < row_size; ++x) { 
    arr[x] = (char *)malloc(col_size * sizeof(char)); 
} 

誰もが言ったように私は...私の列と行がが混在

を持つことができ、あなたがC++を使用していることから、ベクトルがいいです:

auto matrix_like_thing = std::vector<std::vector<char> >(rows, std::vector<char>(cols, '\0')); 
matrix_like_thing[0][4] = 't'; 
1

を使用している場合C++、あなたはたとえば、アクセスを簡単にするために、単純なラッパーを構築することができます:

template <typename T> 
class A2D { 
    T *m_buf; 
    size_t m_n; 
    size_t m_m; 
public: 
    A2D(T *buf, const size_t &n, const size_t &m) 
     : m_buf(buf), m_n(n), m_m(m) { } 
    ~A2D() { } 

    T& operator()(const size_t &i, const size_t &j) 
    { 
     return *(this->m_buf + i * this->m_m + j); 
    } 
}; 

用途:

int main() 
{ 
    int *a = new int[16]; 
    for (int i = 0; i < 16; ++i) { 
     a[i] = i; 
    } 
    A2D<int> b(a, 4, 4); 

    for (int i = 0; i < 4; ++i) { 
     for (int j = 0; j < 4; ++j) { 
      std::cout << b(i, j) << ' '; 
     } 
     std::cout << '\n'; 
    } 
} 

Cでは、プロシージャやマクロでも同様のことができます。 重要なことに、事前割り当てメモリ(1D配列)を制御することを忘れないでください。

2

キャストが機能しないのは、基本的に2次元配列を、それぞれが配列を指すポインタの配列へのポインタに変換しようとしているからです文字の

オプションでは、実際の2次元配列のようにデータにアクセスできるようにするための2つのアダプタクラスを作成することができます。これにより、アレイの両方のエクステントへのアクセスが簡素化され、標準ライブラリを使用するために拡張することができます。

#include <iostream> 
#include <sstream> 
#include <utility> 

template <typename Type, size_t DataSize> 
class MDArray 
{ 
public: 

    struct SDArray 
    { 
     SDArray(Type* data, size_t size) : data_(data), size_(size) {} 
     SDArray(const SDArray& o) : data_(o.data), size_(o.size_) {} 

     size_t size() const { return size_; }; 

     Type& operator[](size_t index) 
     { 
      if(index >= size_) 
       throw std::out_of_range("Index out of range"); 

      return data_[index]; 
     } 

     Type operator[](size_t index) const 
     { 
      if(index >= size_) 
       throw std::out_of_range("Index out of range"); 

      return data_[index]; 
     } 

    private: 

     SDArray& operator=(const SDArray&); 
     Type* const  data_; 
     const size_t size_; 
    }; 

    MDArray(const Type *data, size_t size, size_t dimX, size_t dimY) 
     : dimX_(dimX), dimY_(dimY) 
    { 
     if(dimX * dimY > DataSize) 
      throw std::invalid_argument("array dimensions greater than data size"); 

     if(dimX * dimY != size) 
      throw std::invalid_argument("data size mismatch"); 

     initdata(data, size); 
    } 

    size_t size() const { return dimX_; }; 
    size_t sizeX() const { return dimX_; }; 
    size_t sizeY() const { return dimY_; }; 

    SDArray operator[](const size_t &index) 
    { 
     if(index >= dimY_) 
      throw std::out_of_range("Index out of range"); 

     return SDArray(data_ + (dimY_ * index), dimX_); 
    } 

    const SDArray operator[](const size_t &index) const 
    { 
     if(index >= dimY_) 
      throw std::out_of_range("Index out of range"); 

     return SDArray(data_ + (dimY_ * index), dimX_); 
    } 

private: 

    void initdata(const Type* data, size_t size) 
    { 
     std::copy(data, data + size, data_); 
    } 
    MDArray(const MDArray&); 
    MDArray operator=(const MDArray&); 

    Type   data_[DataSize]; 
    const size_t dimX_; 
    const size_t dimY_; 
}; 


int main() 
{ 
    char data[] = "123456789"; 
    MDArray<char, 100> md(data, 9, 3, 3); 


    for(size_t y = 0; y < md.sizeY(); y++) 
    { 
     for(size_t x = 0; x < md.sizeX(); x++) 
     { 
      std::cout << " " << md[y][x]; 
     } 
     std::cout << std::endl; 
    } 

    std::cout << "-------" << std::endl; 

    for(size_t y = 0; y < md.size(); y++) 
    { 
     const auto& sd = md[y]; 
     for(size_t x = 0; x < sd.size(); x++) 
     { 
      std::cout << " " << sd[x]; 
     } 
     std::cout << std::endl; 
    } 

    std::cout << "-------" << std::endl; 

    for(size_t y = 0; y < md.size(); y++) 
    { 
     auto sd = md[y]; 
     for(size_t x = 0; x < sd.size(); x++) 
     { 
      std::cout << " " << sd[x]; 
     } 
     std::cout << std::endl; 
    } 
} 
+0

@Captian Oblivious有用なデータセットがわずか9である場合、これは機能しますか? 'data2d'にアクセスすると、3x3配列ではなく100x100配列のように扱われるようです... – dinkelk

+0

ああ、そうではありません。私は別の解決策で自分の答えを更新しました。 –

関連する問題