使用std :: fill填充多维数组的安全方法是什么?

时间:2010-10-16 09:14:35

标签: c++ multidimensional-array fill

以下是我正在使用的内容:

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

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

(更新:我之前应该已经明确表示我正在课堂上使用它。)

5 个答案:

答案 0 :(得分:18)

初始化为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])在您的情况下为1sizeof(char)==1),但您可能希望将其保留在那里,以防您想在任何时候更改类型。

在这种特殊情况下(标志数组 - 整数类型)我甚至可以考虑使用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)

之类的其他方法更好。

答案 1 :(得分:2)

它是安全的,二维数组是一个数组数组。由于数组占用了连续的存储空间,所以整个多维事物也会如此。所以是的,没关系,安全和便携。假设您没有询问其他答案所涵盖的样式(因为您使用的是旗帜,我强烈建议std::vector<std::bitset<80> > myFlags(26)

答案 2 :(得分:1)

使用std::fill 填充多维数组的安全方法是什么?

简单的默认初始化为using braced inilization

char flags[26][80]{};

上面的代码会将flags中的所有元素初始化为默认字符。


使用std::fillstd::fill_n的二维数组填充

但是,为了提供不同的值来初始化以上是不够的。选项为std::fillstd::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数组进行概括,我建议使用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);
}

现在您可以像这样初始化flags

fill_2D_array(a.flags, '0'); // flags should be `public` in your class!

See Live Online


使用std::fillstd::fill_n的3-D数组填充

在上述模板函数中再添加一个非模板大小参数,也可以将其引入 3d-array s

#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);
}

See Live Online

答案 3 :(得分: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" /* ... */ };

答案 4 :(得分:-1)

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