views:

98

answers:

3

Here's what I'm using:

class something
{
    char flags[26][80];
} a;

std::fill(&a.flags[0][0], &a.flags[0][0]+26*80, 0);

(Update: I should have made it clear earlier that I'm using this inside a class.)

+2  A: 

it is safe, a two-dimensional array is an array of arrays. Since an array occupied contiguous storage, so the whole multidimensional thing will too. So yeah, it's OK, safe and portable. Assuming you are NOT asking about style, which is covered by other answers (since you're using flags, I strongly recommend std::vector<std::bitset<80> > myFlags(26))

Armen Tsirunyan
Are you certain the bitset would be suitable? I'm just storing either zero or one inside each space in he 2d array. These flags are used to track which positions on the console have been updated with my floodfill routine.
Truncheon
@Truncheon: you store 8 values in a char, right? And in order to get, say, 7th value in the 6th char you must do some bit shifting/anding etc. The bitset will do it for you. That is, it will store each flag in a bit, and you can set/unset each flag by its index without worrying about bit patterns. The only downside is that the bitset's size must be a compile-time constant. If you are familiar with boost, they have dynamic_bitset which is pretty much what its name is.
Armen Tsirunyan
@Armen Tsirunyan: I believe that he is storing a single bit in each byte. That means that using a bitset of 26*80 positions and the appropriate `(row,col)->index` algebra the use of a single `bitset` will be more efficient in memory consumption.
David Rodríguez - dribeas
@David: It will definitely be more efficient in terms of memory, but readability will suffer, that is he will have to write btst[numCols*row+col] which is less readable compared to v[row][col]. The decision is up to the OP and is dependent on his priorities.
Armen Tsirunyan
+3  A: 

The simple way to initialize to 0 the array is in the definition:

char flags[26][80] = {};

If you want to use std::fill, or you want to reset the array, I find this a little better:

char flags[26][80];
std::fill( &flags[0][0], &flags[0][0] + sizeof(flags) /* / sizeof(flags[0][0]) */, 0 );

The fill expressed in terms of the array size will allow you to change the dimensions and keep the fill untouched. The sizeof(flags[0][0]) is 1 in your case (sizeof(char)==1), but you might want to leave it there in case you want to change the type at any point.

In this particular case (array of flags --integral type) I could even consider using memset even if it is the least safe alternative (this will break if the array type is changed to a non-pod type):

memset( &flags[0][0], 0, sizeof(flags) );

Note that in all three cases, the array sizes are typed only once, and the compiler deduces the rest. That is a little safer as it leaves less room for programmer errors (change the size in one place, forget it in the others).

EDIT: You have updated the code, and as it is it won't compile as the array is private and you are trying to initialize it externally. Depending on whether your class is actually an aggregate (and want to keep it as such) or whether you want to add a constructor to the class you can use different approaches.

const std::size_t rows = 26;
const std::size_t cols = 80;
struct Aggregate {
   char array[rows][cols];
};
class Constructor {
public:
   Constructor() {
      std::fill( &array[0][0], &array[rows][0], 0 ); // [1]
      // memset( array, 0, sizeof(array) );
   }
private:
   char array[rows][cols];
};
int main() {
   Aggregate a = {};
   Constructor b;
}

Even if the array is meant to be public, using a constructor might be a better approach as it will guarantee that the array is properly initialized in all instances of the class, while the external initialization depends on user code not forgetting to set the initial values.

[1] As @Oli Charlesworth mentioned in a comment, using constants is a different solution to the problem of having to state (and keep in synch) the sizes in more than one place. I have used that approach here with a yet different combination: a pointer to the first byte outside of the bidimensional array can be obtained by requesting the address of the first column one row beyond the bidimensional array. I have used this approach just to show that it can be done, but it is not any better than others like &array[0][0]+(rows*cols)

David Rodríguez - dribeas
+1 for `char flags[26][80] = {}` :)
Prasoon Saurav
+1. However, an alternative to using `sizeof` is to `#define` (or `const int`) the dimensions. This has the added advantage that it will work if you've passed `flags` as a function argument, so that it's decayed to a pointer so `sizeof` will no longer give the correct result.
Oli Charlesworth
I'm not sure I can use the initializing braces because the 2d array is inside a class. I'll give you a chance to update before I accept.
Truncheon
A: 

Is char[80] supposed to be a substitute for a real string type? In that case, I recommend the following:

std::vector<std::string> flags(26);
flags[0] = "hello";
flags[1] = "beautiful";
flags[2] = "world";
// ...

Or, if you have a C++ compiler that supports initialization lists, for example a recent g++ compiler:

std::vector<std::string> flags { "hello", "beautiful", "world" /* ... */ };
FredOverflow