Advertisement

multidimensional arrays

Started by February 25, 2002 02:26 PM
20 comments, last by evilclown 22 years, 6 months ago
Jason Zelos, I can''t do that because the map will be a global variable. Each new map loaded could be a different size. If it''s global, I can''t change the dimensions without using new.

I want to be able to use a container if possible so I don''t have to worry about new and delete.
why use stl? this is a simple memory allocation problem of a struct. just

  map = (tile*)malloc(width*height);// and access likemap[x*y*width].blah= 42;// free byfree(map);  


i dont see what is so complex about this. need it in a container so you dont have to worry about deletion? face it, if you are dynamically loading maps, your load() function should free the previous map.

if you insist on using stl, then do a search on google or gamedev, maybe even get a book.

you should consider "map" to be a part your map loading class. while you would probally want to leave the map varible public, you could just add functions that do the stuff you need (ie check for collision, load, unload, etc.)
Advertisement
evilcrap''s short multi-dereferencing tutorial

when you work with pointers, after the first dimension, you need to dereference every pointer to get to its value.

1D, a vector
      char* pC = new char[length];cout << pC[x]; //output each char  


2D, a Map
        char** Map = new char*[width];	for(int x = 0; x < width; x++)	Map[x] = new char[height];cout << Map[x][y];  



3d, a Cube
      char*** pMap = new char**[depth]; //create a series of Map pointersfor(z = 0; z < depth; z++){	pMap = new char*[width];	for(x = 0; x < width; x++)		pMap[z][x] = new char[height];} cout << pMap[z][x][y];  

------
if you examine a vector(1D array), then youll notice that the pointer itself is the first element of the array.
           	cout << pChar; //pChar is an address, itll print till it finds a NULL	cout << *pChar; //pChar is a char, itll print pChar[0]  

so, guess at below some.
   	cout << ***pMap; // ? pMap[0][0][0], it is an address	cout << (**pMap)[y]; // ? pMap[0][0][y], it is an address	cout << (*pMap)[x][y]; // ? pMap[0][x][y], it is a char	cout << pMap[z][x][y]; // ? pMap[z][x][y], it is a char  


-note that (*pMap)[y] != *pMap[y]

-although you could simulate any number of dimensions in a single vector, there is a performance cost of having to multiply alot.

-dereferencing is alot faster than multiplying... therefore, if you want your code to be readible and fast, you should use pointers.
Think of it this way. A dynamically allocated 2d-array is an arroy of pointers. Each pointer points to an array, which is itself a pointer. Hence, your "outermost" layer is an array of pointers to pointers. For a cube, you would need pointers to pointers to pointers, each of which would point to a pointer to a pointer, each of which would point to a pointer to a block of memory.

It may seem comfusing, but I''m sure you''ll get to understand it pretty quickly.

An alternative to using multidimensional arrays is to use a 1-dimensional array as a direct address table. This is the simplest form of a technique called hashing. Basically, it takes multiple parameters, and creates a single number from them, which is an array index. A straightforward way to do this in 2d is "the way you read." If you number each array "slot" starting at the top left corner, and going across each row, working from top to bottom, then you get a simple pattern. An often-used function that determines the array index that corresponds to an x, y coordinate is (x + y * width). I''m sure you can extend this technique to three dimensions.
why do ppl confuse things so? you can have a multi dimensional array WITHOUT using arrays of arrays.

there are two types, many ppl seem to ignore this fact. citing c/c++ books that state mulitdimensional arrays must be arrays of arrays (ie 2d array must be decalred "int **blah or int blah[y][x]") this just is not so.

a small tutorial that explains the difference between planar and linear memory and when to use each.

planar mulit dimensional arrays. these is how most ppl seem to think of them, and how evil crap explains it. basically you are creating arrays of pointers to other arrays. see my previous examples or evilcrap''s examples.

access: need to dereference at each level, the [] operator simplfies this.

pros:
easy access using [][][] for nice reading of code.
each row can have a different number of elements to save ram
since memory is not contigous, its more likly all the alloocs will work.

cons:
complex and messy (de)allocation, order does matter
multiple dereferences will slow access slightly (not much)

useful for command histories, consoles buffer (ie quake), or anything else that you dont need the same sized rows.

**********

linear mulit dimensional arrays. this is a standard array that is accessed in a multi dimensional way. these is how video buffers are ussually treated (linear ones anyway). access is done via mathmatics.

ie [x+y*width] for a 2d array, this can be expanded to 3d arrays as well like [x+y*width+z*width*height]. so you get the idea of how to expand to higher dimensions. basically each dimension you add, requires you to multiple by the previous dimensions size.

pros:
easy (de)allocation. just a single new/malloc
contigous memory, may be useful for quick copies with memcpy


cons:
more complex access, which gets harder to read as the dimensions get higher. this naturally can be simplified with some clever macors, but may not be elegant at all.
very large arrays may not be able to be allocated since it requires a single contigous block.
all rows will be the same size

uses:
maps, video buffers, and anything that contigous memory or easy allocation is perffered.

i am sure there are more pros/cons/uses for each style of multi dimensional array. its up to you to measure which type to use (you should try to understand both, since they are both useful).
a person - arrays of arrays are faster for random access. I''ll admit that random access to array elements is rarely needed, though.
Advertisement
quote: Original post by a person
why do ppl confuse things so? you can have a multi dimensional array WITHOUT using arrays of arrays.


Yes. This is one of the very things that it says in the links I provided. It would be nice to encapsulate the array within a class and provide some natural ways of accessing it but, other than that, I don't see any reason to try and get too clever about it.

--
Cats cannot taste sweets.

Edited by - SabreMan on February 27, 2002 5:32:53 AM
Thank you for all the input!
I was asking all these questions because I am making a tile based game. The multi dimensioned array was for the map. For the graphics part, I wanted to be able to have an array to load surfaces in. That way, when the game is running I can load multiple surfaces, and blit them by knowing the index.

Is this right? I don't know what function removes a value in a vector. (Is there STL documentation somewhere that says?) I thought for freesurface I could use just use if(surfaces.at(index)) but I don't know what at() does.

    #include <string>#include <iostream>#include <vector>#include "SDL.h"class graphics {  public:    graphics();    ~graphics();    int LoadSurface(std::string);    void FreeSurface(int);  private:    vector<SDL_Surface*> surfaces;};graphics::graphics() {  //initialize graphics}graphics::~graphics() {  //destroy graphics  while(surfaces.size() > 0) {    FreeSurface(surfaces.size());  }}int graphics::LoadSurface(std::string filename) {  //add a surface to surfaces  SDL_Surface *surface;  surface = SDL_LoadBMP(filename);  if(surface == NULL) {    cerr << "Unable to load " << filename << endl << SDL_GetError() << endl;    return -1;  }  surfaces.push_back(surface);  SDL_FreeSurface(surface);  return surfaces.size();}void graphics::FreeSurface(int index) {  //remove a surface from surfaces  if(index >= surfaces.size() || index < 0) {    return;  }  SDL_FreeSurface(surfaces[index]);  //delete surfaces[index]}  



Edited by - evilclown on February 27, 2002 10:05:42 AM
quote: Original post by evilclown
Is this right? I don't know what function removes a value in a vector. (Is there STL documentation somewhere that says?) I thought for freesurface I could use just use if(surfaces.at(index)) but I don't know what at() does.


You need to use erase() and remove(), however vectors are not really designed for regularly removing and inserting elements, if that's what you are doing. Sounds like you really need that STL documentation. You could try the following sites...

Dinkumware

SGI


The at() function performs bounded access to a vector element. It will return the element at the position you pass, throwing an exception if you request something out of range. If you know the index, you might prefer to use operator[]. Check out those web links and come back if you are unsure.

--
Cats cannot taste sweets.

Edited by - SabreMan on February 27, 2002 11:07:26 AM

This topic is closed to new replies.

Advertisement