18

これはしばらくの間私を悩ませました。多くの場合、「最大」量のデータを保持するために大きなバッファーを作成していることに気づきます。これにより、次のデータ セットのサイズが変更されるたびにバッファを動的に割り当てたり割り当て解除したりする必要がなくなります。

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

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

2D 配列インデックスを使用するこのデータ セットに対して実行したいアルゴリズムがあるとします。したがって、次のようにデータにアクセスできるようにしたいと考えています。

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

このアルゴリズムでは、2D 配列の xlength と ylength が次のようになることがわかっているとします。

int xlength = 3;
int ylength = 3;

この反復では、amountOfData = 9. ただし、次の反復では長さが異なる場合があります。すなわち。それらは可能でxlength = 4あり、ylength = 4与えられamountOfData = 16ます。

2D 配列のインデックスを使用して 1D 配列をキャストできるようなキャストを行いたいと考えています。最初の 1D の長さはわかっています。これは 2Dxlengthとの長さを教えてくれます。したがって、最初の 100 バイトが有用なデータ セットを保持するのに十分な長さである限り、これylengthを使用しなくても簡単に実行できるはずです。newmalloc

気付いた:

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

コンパイラは 2 番目の次元のサイズを認識していないため、機能しません。しかし、私は実行時にそれが何であるかを知っています!

このようになっている根本的な理由は何ですか?回避策はありますか? 何か不足していますか?

4

4 に答える 4

6

実行時に配列の長さがわかれば、2D 配列を使用するのではなく、関数を使用してエミュレートすることで、この問題を解決する方がよいと思います。たとえば、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];
}
于 2013-07-02T03:37:18.720 に答える
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;
    }
}
于 2013-07-02T02:52:53.757 に答える
1

行/列の長さがわかっている場合(行または列の主要な長さなどに応じて)...次のようなものだと思います...

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

... 1D 配列を 2D として扱うため。

2D 動的 C 配列のもう 1 つのこと。

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';
于 2013-07-02T02:51:29.010 に答える
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 配列) を制御することを忘れないことです。

于 2013-07-02T02:52:06.383 に答える