2013-07-02 12 views
15

To mi przeszkadzało przez pewien czas. Wiele razy robię duży bufor, aby pomieścić "maksymalną" ilość danych. Pomaga mi to uniknąć dynamicznego przydzielania i deallocacji bufora za każdym razem, gdy zmienia się rozmiar następnego zestawu danych.Dostęp do tablicy 1D jako tablicy 2D w C++

Na przykład mówię, że mam tablicę, która jest zbyt duża ze względu na jej rzeczywisty rozmiar, ale znam długość użytecznych danych.

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

Powiedzmy, że mam algorytm, który chcę uruchomić na tym zestawie danych, który korzysta z indeksowania tablicy 2D. Tak, chcę być w stanie uzyskać dostęp do danych w następujący sposób:

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

Powiedzmy dla tego algorytmu wiem, że xlength i ylength tablicy 2D będą:

int xlength = 3; 
int ylength = 3; 

tego iteracja, ponieważ amountOfData = 9. Jednak długości mogą być różne dla następnej iteracji. To znaczy. mogą być xlength = 4 i ylength = 4 podane amountOfData = 16.

Chcę wykonać rzut, który pozwoli mi obsadzić tablicę 1D za pomocą indeksowania tablicy 2D. Wiem, ile czasu zajmuje moja początkowa długość 1D, co mówi mi, jak długie są moje 2D xlength i ylength, więc powinno to być łatwe do wykonania bez użycia new lub malloc, o ile początkowe 100 bajtów jest wystarczająco długie, aby pomieściło jakikolwiek pożyteczny zestaw danych Dla mnie.

Zdaję sobie sprawę, że:

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

nie będzie działać, ponieważ kompilator nie zna wielkość drugiego wymiaru. Ale będę wiedzieć, co to jest w czasie wykonywania!

Jaki jest podstawowy powód takiego stanu rzeczy? Czy są jakieś obejścia? Czy brakuje mi czegoś?

+1

Zajrzyj do [wektory] (http://en.cppreference.com/w/cpp/container/vector). –

+0

Jakich typów oczekujesz w data1D? – Amadeus

+0

@ Tomas Badan Użyłem 'char's jako przykładu, ale konkretny przypadek tego problemu powstał dzisiaj, kiedy chciałem uzyskać dostęp do tablicy 1D 'unsigned char's jako tablicy 2D' unsigned short's. Tablica 1D została wypluwana z zastrzeżonego oprogramowania kamery. Chcę uzyskać wynikowy obraz jako dane 2D w pikselach. – dinkelk

Odpowiedz

4

Gdy tylko znać długość tablicy w czasie wykonywania, myślę, że lepiej jest, aby rozwiązać ten problem, nie stosując 2D tablicę, ale emulowania go za pomocą funkcji. Na przykład w 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

Jeśli znasz swój wiersz/długość kolumny (w zależności od wiersza lub kolumny głównej, a co nie) ... Uważam, że jest coś takiego jak ...

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

... leczenia 1D tablicę jako 2D.

Kolejna sprawa dla dynamicznych macierzy C w 2D.

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

mogę mieć moje kolumn i wierszy mieszane choć ...

Podobnie jak wszyscy inni mówili, wektory są miłe, ponieważ używasz C++:

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

Jeśli używasz C++, można zbudować proste opakowanie, aby uprościć dostęp, na przykład:

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

Zastosowanie:

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

Za pomocą C można wykonywać podobne czynności za pomocą procedur lub makr. Co ważne, nie zapominaj o kontroli pamięci wstępnie przydzielonej (tablica 1D).

2

Powód, dla którego rzutowanie nie działa, polega na tym, że zasadniczo próbujesz przekształcić dwuwymiarową tablicę na wskaźnik w tablicę wskaźników, z których każdy wskazuje na tablicę znaków.

Opcja polega na utworzeniu kilku klas adapterów, które umożliwiają dostęp do danych tak, jakby były rzeczywistą tablicą dwuwymiarową. Ułatwi to dostęp do obu zakresów macierzy i może zostać rozszerzony do użycia z biblioteką standardową.

#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 Czy to działa, gdy użyteczny zestaw danych ma tylko 9 długości? Wygląda na to, że podczas dostępu do 'data2d' potraktuje to jak tablicę 100x100, a nie tablicę 3x3 ... – dinkelk

+0

Ah, nie, nie będzie. Zaktualizowałem swoją odpowiedź za pomocą alternatywnego rozwiązania. –