Inițializarea dimensiunii array C ++

Încerc să definim o clasă. Aceasta este ceea ce am:

enum Tile {
GRASS, DIRT, TREE 
};

class Board {
public:
    int toShow;
    int toStore;
    Tile* shown;
    Board (int tsh, int tst);
    ~Board();
};

Board::Board (int tsh, int tst) {
    toShow = tsh;
    toStore = tst;
    shown = new Tile[toStore][toStore]; //ERROR!
}

Board::~Board() {
    delete [] shown;
}

Cu toate acestea, primesc următoarea eroare pe linia indicată - Numai prima dimensiune a unei matrice alocate poate avea o dimensiune dinamică.

Ceea ce vreau să fac este mai degrabă decât codul greu, să treacă parametrulShow-ul către constructor și să creez o matrice bidimensională care conține doar elementele pe care vreau să le afișez.

Cu toate acestea, înțelegerea mea este că atunci când constructorul este chemat și afișat este inițializat, mărimea acestuia va fi inițializată la valoarea curentă a toStore. Apoi, chiar dacă toStore se schimbă, memoria a fost deja alocată matricei afișate și prin urmare dimensiunea nu trebuie să se schimbe. Cu toate acestea, compilatorul nu-i place acest lucru.

Există o adevărată concepție greșită în ceea ce înțeleg acest lucru? Are cineva o soluție care va face ceea ce vreau fără să trebuiască să codifică greu în dimensiunea matricei?

0
Vedeți această întrebare și răspunsurile sale pentru "cele mai bune practici": Cum mă descurc cel mai bine în rețelele multidimensionale dinamice în C/C ++?
adăugat autor HostileFork, sursa
adăugat autor R. Martinho Fernandes, sursa
Mai întâi, veți dori un indicator 2D: Tile ** shown . Citiți puțin. Odată ce ați învățat cum să faceți acest lucru, utilizați în schimb std :: vector .
adăugat autor chris, sursa
@R.MartinhoFernandes, a trebuit să râd de efortul care a intrat în asta pentru motivul pe care l-ai descris. Mi-am făcut propriile mele xarray cu varargs în stil C odată la un moment dat.
adăugat autor chris, sursa
În afară de ceea ce au fost spus de oameni - aveți un punct și virgulă dorit chiar înainte de comentariu.
adăugat autor Andrejs Cainikovs, sursa

4 răspunsuri

Este bine să înțelegeți puțin cum funcționează alocarea memsauiei în C și C ++.

char x[10];

Compilatsauul va aloca zece octeți și va aminti adresa de psaunire, poate că este la 0x12 (în viața reală, probabil un număr mult mai mare.)

x[3] = 'a';

Acum, compilatsauul caută x [3] prin preluarea adresei de start x , care este 0x12 (char) , care aduce la 0x15 . Deci, x [3] trăiește la 0x15 .

Această aritmetică complementară simplă este modul în care este accesată memsauia din interisauul unei matrice. Pentru matricele bidimensionale matematica este puțin mai complicată.

char xy[20][30];

Alocă 600 de octeți începând de la un loc, poate este 0x2000 . Accesând acum

xy[4][3];

Necesită unele matematici ... xy [0] [0], xy [0] [1], xy [0] [2] ... vsau ocupa primii 30 de octeți. Apoi xy [1] [0], xy [1] [1], ... vsau ocupa octeți de la 31 la 60. Este multiplicare: /code> va fi localizat la adresa xy , plus a * 20, plus b.

Acest lucru este posibil numai dacă compilatsauul știe cât timp este prima dimensiune - veți observa compilatsauul necesar pentru a cunoaște numărul "20" pentru a face acest matematică.

Acum, apelurile funcționale. Compilatsauul nu are niciun grijă dacă sună

foo(int* x);

sau

foo(int[] x);

Because in either case it's an array of bytes, you pass the starting address, and the compiler can do the additional to find the place at which x[3] sau whatever lives. But in the case of a two dimensional array, the compiler needs to know that magic number 20 in the above example. So

foo(int[][] xy) {
    xy[3][4] = 5;     //compiler has NO idea where this lives 
                      //because it doesn't know the row dimension of xy!
}

Dar dacă specificați

foo(int[][30] xy)

Compiler knows what to do. Fsau reasons I can't remember it's often considered better practice to pass it as a double pointer, but this is what's going on at the technical level.

0
adăugat
Mulțumiri. Asta are mult mai mult sens.
adăugat autor user1413793, sursa

Permiteți-mi să vă spun despre ce am făcut când aveam nevoie de o gamă 3D. Ar putea fi o suprasolicitare, dar este destul de rece și ar putea ajuta, deși este un mod complet diferit de a face ceea ce vrei.

Trebuia să reprezint o cutie 3D de celule. Doar o parte din celule au fost marcate și au fost de interes. Au existat două opțiuni pentru a face acest lucru. Prima, declarând o matrice 3D statică cu cea mai mare dimensiune posibilă și folosiți o porțiune din ea dacă una sau mai multe dintre dimensiunile casetei au fost mai mici decât dimensiunile corespunzătoare din matricea statică.

Al doilea mod a fost să aloce și să aloce dinamic matricea. Este un efort destul cu o matrice 2D, ca să nu mai vorbim de 3D.

Soluția matricei a definit o matrice 3D cu celulele de interes având o valoare specială. Cea mai mare parte a memoriei alocate nu a fost necesară.

I dumped both ways. Instead I turned to STL map. I define a struct called Cell with 3 member variables, x, y, z which represented coordinates. The constructor Cell(x, y, z) was used to create such a Cell easily. I defined the operator < upon it to make it orderable. Then I defined a map. Adding a marked cell with coordinates x, y, z to the map was done simply by

my_map [Celula (x, y, z)] = mea_data;

În acest fel nu am avut nevoie să menținem gestionarea memoriei 3D a matricei și, de fapt, doar celulele necesare au fost create.

Verificarea dacă există un apel la coordonatele x0, y0, z0 (sau marcat) a fost făcut prin:

map::iterator it = my_map.find(Cell(x0, y0, z0));
if (it != my_map.end()) { ...

And referencing the cell's data at coordinat x0, y0, z0 was done by: my_map[Cell(x0, y0, z0)]...

Acest metodic ar părea ciudat, dar este robust, auto-gestionat în ceea ce privește memoria și sigur - fără depășire a limitelor.

0
adăugat

Folosiți containerele C ++, pentru care sunt acolo.

class Board {
public:
    int toShow;
    int toStore;
    std::vector > shown;
    Board (int tsh, int tst) : 
      toShow(tsh), toStore(tst), 
      shown(tst, std::vector(tst))
    {
    };
};

...

    Board board(4, 5);
    board.shown[1][3] = DIRT;
0
adăugat
Mulțumiri. Mă întrebam dacă există o modalitate de a face acest lucru cu mănunchiuri, dar acum că am folosit vectori, mi-a făcut viața mai ușoară. De fapt, am decis să folosesc un vector de matrice 1D.
adăugat autor user1413793, sursa

Puteți utiliza o matrice unidimensională. Ar trebui să știți că matricele bi-dimensionale sunt tratate ca matrice unidimensionale și când doriți o dimensiune variabilă puteți utiliza acest model. de exemplu :

int arr1[ 3 ][ 4 ] ;
int arr2[ 3 * 4 ] ;

Ele sunt aceleași și membrii lor pot fi accesați prin diferite notații:

int x = arr1[ 1 ][ 2 ] ;
int x = arr2[ 1 * 4 + 2 ] ;

Desigur, arr1 poate fi văzută ca o matrice de 3 rânduri x 4 coli și o matrice de 3 coloane x 4 rânduri. Cu acest tip de matrice multidimensionale le puteți accesa printr-un singur indicator, dar trebuie să știți despre structura sa internă. Acestea sunt un tablouri de dimensiuni care sunt tratate ca 2 sau 3 dimensionale.

0
adăugat
Multumesc pentru ajutor. Asta am încercat să înțeleg
adăugat autor user1413793, sursa
Cu plăcere. Pot adăuga mai multe explicații dacă nu sunteți în regulă cu asta.
adăugat autor Kamran Amini, sursa