Access a 1D array as a 2D array in C++

后端 未结 4 1802
被撕碎了的回忆
被撕碎了的回忆 2021-01-03 23:26

This has bothered me for a while. A lot of times I find myself making a large buffer to hold a \"maximum\" amount of data. This helps me avoid dynamically allocating and dea

相关标签:
4条回答
  • 2021-01-03 23:55

    The reason the cast does not work is you are essentially trying to convert a 2 dimensional array to a pointer to an array of pointers that each point to an array of characters.

    On option is to create a couple of adapter classes that allow you to access the data as if it were an actual two dimensional array. This will simplify access to both extents of the array and can be extended for usage with the standard library.

    #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 讨论(0)
  • 2021-01-04 00:08

    Once you only know the length of your array at runtime, I guess it is better to solve this problem not using an 2D array, but emulating it by using functions. For example, in 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];
    }
    
    0 讨论(0)
  • 2021-01-04 00:13

    If you are using C++, you can build a simple wrapper to simplify an access, for example:

    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);
        }
    };
    

    Usage:

    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';
        }
    }
    

    With C you can do the similar things with procedures or macros. Importantly, do not forget to control preallocated memory (1D array)

    0 讨论(0)
  • 2021-01-04 00:15

    If you know your row/column length (depending on row or column major and what not)... I believe it's something like...

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

    ... for treating a 1D array as 2D.

    Another thing for 2D dynamic C arrays.

    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));
    }
    

    I could have my columns and rows mixed though...

    Like everyone else has said, vectors are nice since you're using C++:

    auto matrix_like_thing = std::vector<std::vector<char> >(rows, std::vector<char>(cols, '\0'));
    matrix_like_thing[0][4] = 't';
    
    0 讨论(0)
提交回复
热议问题