【发布时间】:2023-03-14 19:42:01
【问题描述】:
这是我正在使用的:
class something
{
char flags[26][80];
} a;
std::fill(&a.flags[0][0], &a.flags[0][0] + 26 * 80, 0);
(更新:我应该早点说清楚我在一个类中使用它。)
【问题讨论】:
标签: c++ arrays algorithm multidimensional-array fill
这是我正在使用的:
class something
{
char flags[26][80];
} a;
std::fill(&a.flags[0][0], &a.flags[0][0] + 26 * 80, 0);
(更新:我应该早点说清楚我在一个类中使用它。)
【问题讨论】:
标签: c++ arrays algorithm multidimensional-array fill
初始化为0数组的简单方法在定义中:
char flags[26][80] = {};
如果你想使用std::fill,或者你想重置数组,我觉得这样好一点:
char flags[26][80];
std::fill( &flags[0][0], &flags[0][0] + sizeof(flags) /* / sizeof(flags[0][0]) */, 0 );
以数组大小表示的fill 将允许您更改尺寸并保持fill 不变。在您的情况下,sizeof(flags[0][0]) 是 1 (sizeof(char)==1),但您可能希望将其保留在那里,以防您想随时更改类型。
在这种特殊情况下(flags --integral 类型的数组)我什至可以考虑使用memset,即使它是最不安全的替代方案(这会破坏如果数组类型改为非pod类型):
memset( &flags[0][0], 0, sizeof(flags) );
请注意,在所有三种情况下,数组大小只输入一次,其余的由编译器推断。这更安全一些,因为它为程序员错误留出了更少的空间(在一个地方更改大小,在其他地方忘记它)。
编辑:您已经更新了代码,因为它不会编译,因为数组是私有的并且您正在尝试在外部对其进行初始化。根据您的类是否实际上是一个聚合(并希望保留它)或者您是否想向该类添加一个构造函数,您可以使用不同的方法。
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;
}
即使array 是公开的,使用构造函数可能是更好的方法,因为它可以保证array 在类的所有实例中正确初始化,而外部初始化取决于用户代码不要忘记设置初始值。
[1] 正如@Oli Charlesworth 在评论中提到的,对于必须在多个位置声明(并保持同步)大小的问题,使用常量是一种不同的解决方案。我在这里使用了这种方法,但组合却不同:可以通过请求二维数组之外的第一列的地址来获得指向二维数组之外的第一个字节的指针。我使用这种方法只是为了表明它是可以做到的,但它并不比&array[0][0]+(rows*cols)等其他方法更好
【讨论】:
sizeof 的替代方法是使用#define(或const int)尺寸。这还有一个额外的好处,如果您将 flags 作为函数参数传递,它将起作用,因此它会衰减为指针,因此 sizeof 将不再给出正确的结果。
fill(&arr[0], &arr[0] + sizeof(arr), 0) )不适用于一维数组吗?
sizeof 运算符为您提供以字节为单位的大小,而不是元素的数量,如果 arr 包含任何诸如 sizeof(*arr) != 1 以上具有未定义的行为并且可能会崩溃(尝试访问超出数组末尾的内容)。否则(即如果数组包含[unsigned|signed] char,它应该可以工作
使用
std::fill填充多维数组的安全方法是什么?
简单的默认初始化是using braced inilization。
char flags[26][80]{};
上面会将flags中的所有元素初始化为默认字符。
std::fill 或std::fill_n 填充二维数组
但是,为了提供不同的值来初始化以上是不够的。选项为std::fill 和std::fill_n。 (假设你的类中数组flags是public)
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');
为了将这一点推广到具有任何初始化值的任何类型的任何 2d-array,我建议a templated function 如下。这也将避免 sizeof 计算数组中的总元素。
#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);
}
现在你可以初始化你的flagslike
fill_2D_array(a.flags, '0'); // flags should be `public` in your class!
std::fill 或std::fill_n 填充3-D 数组
在上面的模板函数中再增加一个非模板大小参数,这个也可以带入到3d-arrays中
#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);
}
【讨论】:
是安全的,二维数组是数组的数组。由于数组占用了连续的存储空间,所以整个多维的东西也会。所以,是的,它没关系,安全且便携。假设您不询问样式,其他答案已涵盖(因为您使用的是标志,我强烈推荐 std::vector<std::bitset<80> > myFlags(26))
【讨论】:
(row,col)->index 代数使用单个bitset 将更有效地消耗内存。
char flags[26][80];
std::fill((char*)flags, (char*)flags + sizeof(flags)/sizeof(char), 0);
【讨论】:
char[80] 是否应该替代真正的字符串类型?在这种情况下,我建议如下:
std::vector<std::string> flags(26);
flags[0] = "hello";
flags[1] = "beautiful";
flags[2] = "world";
// ...
或者,如果您有支持初始化列表的 C++ 编译器,例如最近的 g++ 编译器:
std::vector<std::string> flags { "hello", "beautiful", "world" /* ... */ };
【讨论】: