2D阵列中的记忆集

时间:2019-05-06 14:54:52

标签: c++ arrays loops memset

我对静态2D数组有疑问。我想重设第k + 1行之后的元素,并想使用memset。

我编写了这段代码,但是它没有重置第k + 1行之后的所有行:

int a[505][505];
..................
for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
         f >> a[i][j];
memset(a + k + 1 , 0 , sizeof(int) * (m + 1) * (n - k));

此代码不会重置第k + 1行之后的所有行。

编辑:n = 2d数组具有多少行m = 2d数组具有多少列

编辑:我有一个更大的问题,每当我在问题中做某件事时,都需要重设第k + 1条线。

2 个答案:

答案 0 :(得分:4)

数组的索引从.img@style开始。因此,如果您有0个元素的数组,则索引的有效范围是N

这里是一个演示程序,显示了如何将函数[0, N)与整数数组一起使用。

memset

其输出为

#include <iostream>
#include <iomanip>
#include <cstring>

int main()
{
    const size_t N = 5;
    const size_t M = 10;
    int a[N][M];

    size_t k = 2;

    for ( size_t i = 0; i < k; i++ )
    {
        for ( size_t j = 0; j < M; j++ ) a[i][j] = M * i + j;
    }

    std::memset( a[k], 0, ( N - k ) * M * sizeof( int ) );

    for ( const auto &row : a )
    {
        for ( const auto &value : row ) std::cout << std::setw( 2 ) << value << ' ';
        std::cout << '\n';
    }        
}

如果您只想将零重置为零(例如第k行),则调用memset的过程将类似于

 0  1  2  3  4  5  6  7  8  9 
10 11 12 13 14 15 16 17 18 19 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  0  0  0 

更通用的方法是使用标准算法std::memset( a[k], 0, M * sizeof( int ) ); 。例如

std::fill

例如

std::fill( std::begin( a[k] ), std::end( a[k] ), 0 );

程序首先顺序填充数组的所有元素,然后将第k行重置为零。

当然,最初声明数组以零初始化而不需要调用函数#include <iostream> #include <iomanip> #include <iterator> #include <algorithm> int main() { const size_t N = 5; const size_t M = 10; int a[N][M]; size_t k = 2; for ( size_t i = 0; i < N; i++ ) { for ( size_t j = 0; j < M; j++ ) a[i][j] = M * i + j; } std::fill( std::begin( a[k] ), std::end( a[k] ), 0 ); for ( const auto &row : a ) { for ( const auto &value : row ) std::cout << std::setw( 2 ) << value << ' '; std::cout << '\n'; } } (编译器会自己完成)会更简单。

memset

答案 1 :(得分:4)

我们在这里不做C ...,请使用带有比M和N多的字母的标识符。

#include <cstddef>
#include <iostream>
#include <algorithm>
#include <numeric>
#include <iterator>

template<typename T, std::size_t ROWS, std::size_t COLS>
void print_arr(T (&arr)[COLS][ROWS])
{
    for (size_t row{}; row < ROWS; ++row) {
        std::copy(&arr[row][0], &arr[row][0] + COLS,
                  std::ostream_iterator<T>{ std::cout, "\t" });
        std::cout.put('\n');
    }
    std::cout.put('\n');
}

template<typename T, std::size_t ROWS, std::size_t COLS>
void kill_all_from_line_till_last(T (&arr)[COLS][ROWS], std::size_t kill_from)
{
    std::fill(&arr[kill_from][0], &arr[kill_from][0] + (ROWS - kill_from) * COLS, T{});
}

int main()
{
    constexpr size_t rows    { 10 };
    constexpr size_t columns { 10 };

    int arr[rows][columns];
    std::iota(&arr[0][0], &arr[0][0] + columns * rows, 1);
    print_arr(arr);

    kill_all_from_line_till_last(arr, 7);

    print_arr(arr);
}

输出:

1       2       3       4       5       6       7       8       9       10
11      12      13      14      15      16      17      18      19      20
21      22      23      24      25      26      27      28      29      30
31      32      33      34      35      36      37      38      39      40
41      42      43      44      45      46      47      48      49      50
51      52      53      54      55      56      57      58      59      60
61      62      63      64      65      66      67      68      69      70
71      72      73      74      75      76      77      78      79      80
81      82      83      84      85      86      87      88      89      90
91      92      93      94      95      96      97      98      99      100

1       2       3       4       5       6       7       8       9       10
11      12      13      14      15      16      17      18      19      20
21      22      23      24      25      26      27      28      29      30
31      32      33      34      35      36      37      38      39      40
41      42      43      44      45      46      47      48      49      50
51      52      53      54      55      56      57      58      59      60
61      62      63      64      65      66      67      68      69      70
0       0       0       0       0       0       0       0       0       0
0       0       0       0       0       0       0       0       0       0
0       0       0       0       0       0       0       0       0       0

伪C版本:

...使用std::memset()看起来几乎相同:

#include <cstring>

template<typename T, std::size_t ROWS, std::size_t COLS>
void kill_all_from_line_till_last(T (&arr)[COLS][ROWS], std::size_t kill_from)
{
    std::memset(&arr[kill_from][0], 0, (ROWS - kill_from) * COLS * sizeof(T));
}

但您只能将其用于POD。


速度:

由于您提到发现std::fill()相对于std::memset()而言太慢了

@Sochuu:

  

填充有效,但速度太慢。我想要memset

constexpr size_t rows    { 10 };
constexpr size_t columns { 10 };
{
    int arr[rows][columns];
    std::iota(&arr[0][0], &arr[0][0] + columns * rows, 1);
    print_arr(arr);
    kill_all_from_line_till_last_fill(arr, 7);
    print_arr(arr);
}
{
    int arr[rows][columns];
    std::iota(&arr[0][0], &arr[0][0] + columns * rows, 1);
    print_arr(arr);
    kill_all_from_line_till_last_memset(arr, 7);
    print_arr(arr);
}

gcc

从gcc 9.1(--std=c++14 -O3 -Wall)开始的组装:

    ; ...

    call    void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
    xor     eax, eax
    mov     ecx, 15
    mov     rdi, rbx
    rep stosq
    mov     rdi, rsp
    call    void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])

    ; ...

    call    void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
    xor     eax, eax
    mov     rdi, rbx
    mov     ecx, 15
    rep stosq
    mov     rdi, rsp
    call    void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])

    ; ...

如您所见,对于两个版本,在对print_arr()的调用之间会生成完全相同的代码。编译器并不愚蠢。

完整代码:godbolt Compiler Explorer


c

与clang 8.3.0(--std=c++14 -Ofast3 -Wall)相同,两者的代码完全相同,std::fill()std::memset()

    ; ...

    mov     rdi, rbx
    call    void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
    xorps   xmm0, xmm0
    movups  xmmword ptr [rsp + 376], xmm0
    movups  xmmword ptr [rsp + 360], xmm0
    movups  xmmword ptr [rsp + 344], xmm0
    movups  xmmword ptr [rsp + 328], xmm0
    movups  xmmword ptr [rsp + 312], xmm0
    movups  xmmword ptr [rsp + 296], xmm0
    movups  xmmword ptr [rsp + 280], xmm0
    mov     qword ptr [rsp + 392], 0
    mov     rdi, rbx
    call    void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])

    ; ...

    call    void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])
    xorps   xmm0, xmm0
    movups  xmmword ptr [rsp + 376], xmm0
    movups  xmmword ptr [rsp + 360], xmm0
    movups  xmmword ptr [rsp + 344], xmm0
    movups  xmmword ptr [rsp + 328], xmm0
    movups  xmmword ptr [rsp + 312], xmm0
    movups  xmmword ptr [rsp + 296], xmm0
    movups  xmmword ptr [rsp + 280], xmm0
    mov     qword ptr [rsp + 392], 0
    mov     rdi, rbx
    call    void print_arr<int, 10ul, 10ul>(int (&) [10ul][10ul])

    ; ...

完整代码:godbolt Compiler Explorer


msvc

Microsoft cl 19.20(/O2):

    ; ...

    call    void print_arr<int,10,10>(int (&)[10][10])
    xorps   xmm0, xmm0
    lea     rcx, QWORD PTR arr$2[rsp]
    xor     eax, eax
    movups  XMMWORD PTR arr$2[rsp+280], xmm0
    mov     QWORD PTR arr$2[rsp+392], rax
    movups  XMMWORD PTR arr$2[rsp+296], xmm0
    movups  XMMWORD PTR arr$2[rsp+312], xmm0
    movups  XMMWORD PTR arr$2[rsp+328], xmm0
    movups  XMMWORD PTR arr$2[rsp+344], xmm0
    movups  XMMWORD PTR arr$2[rsp+360], xmm0
    movups  XMMWORD PTR arr$2[rsp+376], xmm0
    call    void print_arr<int,10,10>(int (&)[10][10])     ; 

    ; ...

    call    void print_arr<int,10,10>(int (&)[10][10])
    xorps   xmm0, xmm0
    lea     rcx, QWORD PTR arr$1[rsp]
    xor     eax, eax
    movups  XMMWORD PTR arr$1[rsp+280], xmm0
    mov     QWORD PTR arr$1[rsp+392], rax
    movups  XMMWORD PTR arr$1[rsp+296], xmm0
    movups  XMMWORD PTR arr$1[rsp+312], xmm0
    movups  XMMWORD PTR arr$1[rsp+328], xmm0
    movups  XMMWORD PTR arr$1[rsp+344], xmm0
    movups  XMMWORD PTR arr$1[rsp+360], xmm0
    movups  XMMWORD PTR arr$1[rsp+376], xmm0
    call    void print_arr<int,10,10>(int (&)[10][10])

    ; ...

完整代码:godbolt Compiler Explorer

我认为实验可以在这一点上结束。