我对静态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条线。
答案 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
...使用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 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
与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
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
我认为实验可以在这一点上结束。