AlmostSurely
AlmostSurely

Reputation: 562

2d Vector Initialization

I gave up on trying to pass a 2d array to a function, where the dimensions are not known at compile time. After some research, it seems like a 2d vector may be a good substitute. I just want to confirm that this is the correct way to declare a 2d vector of dimension totalRows X totalColumns, initializaing each cell to contain the space character:

vector<vector<char> > world(totalRows, vector<char>(totalColumns, ' '));

Upvotes: 2

Views: 8853

Answers (2)

user1309389
user1309389

Reputation:

The line itself should work and looks fine. But let me offer a bit more information.

It is a good idea to try and make use of the standard library. With that said, you need to understand that the image of a 2D array you have in your head must exist linearly in memory. You can easily create an m*n element vector of chars (in your example) and index it row-major wise as (i*n + j) (courtesy of zero-based counting).

In fact, that's the way "two dimensional" arrays work. For example, when you do a regular array of elements - T[][], if you try to decay it into a pointer, it'll be a simple T*. Under the hood, memory is laid out contiguously and linearly, there are no shapes, just one long street (as the computer sees it). And it simply infers the notion of rows and columns as humans see it by using the expression (or a similar one) in the first paragraph. The computer doesn't care.

vector is a nice part of the standard library which encapsulates arrays in a way that is signature C++ (and not just bloated C). Its very design enables easy resizing of the internal array data structure and with the advent of C++11, move semantics can make resizing an even cheaper operation. Also, the notions of RAII apply here, ideas of carefully initializing data members in constructors and relieving them in destructors enable you to evade issues of dynamic memory allocation as a user and simply propagate new objects on the stack, passing references when they need to "exit" their scope.

One thing to note is that vectors create an internal block of memory, an array which might exceed at times the size of the actual array, because of popping and pushing new elements. Also, you're not obliged to define the size of it at first, but can easily extend it by push_back, push_front etc. This means that other things can change on the fly and extending can cost you quite a bit, even with move semantics.

The only reason to stray from vectors is when you're doing some heavy 3D rendering or simulations that are data-oriented and expect the data to be packed in some very custom, specific ways and be shuffled around manually which the tidy vector might not easily allow. But that will push you into more low-level realms of naked arrays (and you ought to be ready for it). The key things that you should take from this is that you can simply treat "mental 2D array" vectors(really, data has no real geometric shape, that's just how we, puny humans, see it) as vectors and just index them differently. Make sure you input all the row data, in sequence, one by one and you'll get a very simple layout which can be simply probed/indexed with (i*n + j) where [i,j] is the classic 2D matrix subscripting/indexing.

Then, it could be as simple as:

vector<char> world(totalRows*totalColumns, ' ');

And then you simply pass by reference where it needs to go, indexing it as (i*n + j) after you push the data on it properly.

Your code should work, but the unnecessary bloat might introduce unnecessary mental overhead while trying to manipulate your data, shifting it around and writing unnecessary stuff, much less than actually using the i*n+j "manual indexing" approach to keep your mental picture of a 2D array/matrix of chars. If you're willing, you could even override functionality in order to add syntactic sugar.

Upvotes: 9

Synxis
Synxis

Reputation: 9388

Your code works. As noticed in the comment, vector<vector<T>> is not truly a 2D array.

The important thing here is that (totalRows, vector<char>(totalColumns, ' ')) and (totalColumns, vector<char>(totalRows, ' ')) are equivalent, as long as you always follow the rule used to create the vector: line x column (or column x line)

Upvotes: 4

Related Questions