Here is what I am 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 am using this inside a class.)
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)
fill(&arr[0], &arr[0] + sizeof(arr), 0) doesn't work for a 1D array?sizeof operator gives you the size in bytes, not the number of elements, if arr holds anything such that sizeof(*arr) != 1 the above has undefined behavior and will probably crash (try to access well beyond the end of the array). Otherwise (i.e. if the array holds [unsigned|signed] char, it should be workingflags[0][0] is an element of the 80-element array flags[0] but &flags[0][0] + sizeof(flags) takes us well outside of flags[0]. Yes, it would be natural for this to take us into/through the other arrays in flags (flags[1], flags[2], flags[3], etc.) and yes, the standard guarantees the memory layout makes this sensible, but I still don't see what guarantees that this arithmetic is valid when arithmetic taking you outside your starting array normally yields undefined behavior.char.std::fill with pointers over the innermost array range.What is the safe way to fill multidimensional array using
std::fill?
The easy default initialization would be using braced inilization.
char flags[26][80]{}; The above will initialize all the elements in the flags to default char.
std::fill or std::fill_nHowever, in order to provide different value to initialize the above is not enough. The options are std::fill and std::fill_n. (Assuming that the array flags is public in your class)
std::fill( &a.flags[0][0], &a.flags[0][0] + sizeof(a.flags) / sizeof(a.flags[0][0]), '0'); // or using `std::fill_n` // std::fill_n(&a.flags[0][0], sizeof(a.flags) / sizeof(a.flags[0][0]), '1'); To generalize this for any 2d-array of any type with any initializing value, I would suggest a templated function as follows. This will also avoid the sizeof calculation of the total elements in the array.
#include <algorithm> // std::fill_n, std::fill #include <cstddef> // std::size_t template<typename Type, std::size_t M, std::size_t N> constexpr void fill_2D_array(Type(&arr2D)[M][N], const Type val = Type{}) noexcept { std::fill_n(&arr2D[0][0], M * N, val); // or using std::fill // std::fill(&arr2D[0][0], &arr2D[0][0] + (M * N ), val); } Now you can initialize your flags like
fill_2D_array(a.flags, '0'); // flags should be `public` in your class! std::fill or std::fill_nAdding one more non-template size parameter to the above template function, this can be brought to 3d-arrays as well
#include <algorithm> // std::fill_n #include <cstddef> // std::size_t template<typename Type, std::size_t M, std::size_t N, std::size_t O> constexpr void fill_3D_array(Type(&arr3D)[M][N][O], const Type val = Type{}) noexcept { std::fill_n(&arr3D[0][0][0], M * N * O, val); } 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))
(row,col)->index algebra the use of a single bitset will be more efficient in memory consumption.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" /* ... */ }; The problem isn't that you can't fill a 2D array by passing appropriate pointer(s) to a function. It's pretty clear that if you write a function that, for instance, takes a T* and a count of rows*cols and assumes a contiguous set of T's, it will compile and happily fill the 2D array. The function doesn't know anything about the structure of the 2D array. It just gets a pointer and length.
The problem is the compiler knows the structure. And it knows that if you pass a pointer to an element in the 2D array, the only values that can be modified according to the language, are the ones in the sub-array that the pointer addressed. So the compiler can assume all other values outside of that subarray will not be altered. The language guarantees that. And compiler optimizers can take advantage to speed up code.
This is similar to the problem of signed int overflow. While signed overflow is well defined in two's complement arithmetic, compilers are free to assume it never happens because it is prohibited by the language. This opens up optimization opportunities and compilers take advantage to speed up code.
So no, You can't use std::fill to initialize the contents of a multi-dimensional array. The C++ language is rather strict on what pointers are allowed to point to. Even without de-referencing them! The following code shows std::fill failing when trying to initialize the entire array. It also shows that simply incrementing the pointer to one past the last element is UB.
#include <algorithm> constexpr bool foo() { char matrix[2][10]{}; std::fill(&matrix[0][0], &matrix[0][10], 0); // works std::fill(&matrix[1][0], &matrix[1][10], 0); // works // std::fill(&matrix[0][0], &matrix[1][10], 0); // fails, UB detected char* pc = &matrix[0][10]; // Legal. points to one past the last element of the lower, 10 char array. // pc = &matrix[0][10]+1; // UB. points to two past the last element of the lower, 10 char array. return true; } constexpr bool x = foo(); int main() { return x; } Code in Compiler Explorer