C에서 큰 2d 배열을 반복적으로 제로화하고 싶습니다. 이것이 제가 지금하는 일입니다.
// Array of size n * m, where n may not equal m
for(j = 0; j < n; j++)
{
for(i = 0; i < m; i++)
{
array[i][j] = 0;
}
}
memset을 사용해 보았습니다.
memset(array, 0, sizeof(array))
그러나 이것은 1D 배열에서만 작동합니다. 2D 배열의 내용을 인쇄하면 첫 번째 행은 0이지만 임의의 큰 숫자가로드되어 충돌합니다.
답변
memset(array, 0, sizeof(array[0][0]) * m * n);
어디 m
와 n
2 차원 배열의 폭과 높이 (귀하의 예제에서, 당신이 그렇게, 사각형 2 차원 배열을 가지고 있습니다 m == n
).
답변
경우 array
진정으로 배열입니다, 당신은 함께 “그것을 밖으로 제로”할 수 있습니다 :
memset(array, 0, sizeof array);
그러나 알아야 할 두 가지 사항이 있습니다.
- 이것은
array
실제로 “2 차원 배열”인 경우에만 작동합니다 . 즉,T array[M][N];
일부 유형에 대해 선언 되었습니다T
. array
선언 된 범위에서만 작동합니다 . 당신이 함수에 전달하면, 그 이름은array
포인터로 붕괴 , 그리고sizeof
당신에게 배열의 크기를 제공하지 않습니다.
실험을 해보자 :
#include <stdio.h>
void f(int (*arr)[5])
{
printf("f: sizeof arr: %zu\n", sizeof arr);
printf("f: sizeof arr[0]: %zu\n", sizeof arr[0]);
printf("f: sizeof arr[0][0]: %zu\n", sizeof arr[0][0]);
}
int main(void)
{
int arr[10][5];
printf("main: sizeof arr: %zu\n", sizeof arr);
printf("main: sizeof arr[0]: %zu\n", sizeof arr[0]);
printf("main: sizeof arr[0][0]: %zu\n\n", sizeof arr[0][0]);
f(arr);
return 0;
}
내 컴퓨터에서 위의 내용이 인쇄됩니다.
main: sizeof arr: 200
main: sizeof arr[0]: 20
main: sizeof arr[0][0]: 4
f: sizeof arr: 8
f: sizeof arr[0]: 20
f: sizeof arr[0][0]: 4
arr
은 배열 이지만 에 전달 될 때 첫 번째 요소에 대한 포인터로 축소 f()
되므로 인쇄 된 크기 f()
가 “잘못된”것입니다. 또한 f()
의 크기 는 “array [5] of “인 arr[0]
배열의 크기입니다 . “감쇠”는 첫 번째 수준에서만 발생하기 때문에 의 크기가 아니므 로 올바른 크기의 배열에 대한 포인터를 사용하는 것으로 선언해야합니다 .arr[0]
int
int *
f()
그래서 제가 말했듯이, 당신이 원래하던 일은 위의 두 가지 조건이 충족 되어야만 작동 할 것입니다. 그렇지 않은 경우 다른 사람이 말한대로해야합니다.
memset(array, 0, m*n*sizeof array[0][0]);
마지막으로 게시 memset()
한 for
루프는 엄격한 의미에서 동일하지 않습니다. 포인터 및 부동 소수점 값과 같은 특정 유형에 대해 “모든 비트 0″이 0이 아닌 컴파일러가있을 수 있습니다. 나는 당신이 그것에 대해 걱정할 필요가 있는지 의심합니다.
답변
글쎄요, 가장 빠른 방법은 전혀하지 않는 것입니다.
내가 아는 이상하게 들리는데, 여기에 의사 코드가 있습니다.
int array [][];
bool array_is_empty;
void ClearArray ()
{
array_is_empty = true;
}
int ReadValue (int x, int y)
{
return array_is_empty ? 0 : array [x][y];
}
void SetValue (int x, int y, int value)
{
if (array_is_empty)
{
memset (array, 0, number of byte the array uses);
array_is_empty = false;
}
array [x][y] = value;
}
실제로, 여전히 배열을 지우고 있지만 배열에 무언가가 기록 될 때만 가능합니다. 이것은 여기서 큰 이점이 아닙니다. 그러나 2D 배열이 쿼드 트리 (동적 한 마음이 아님) 또는 데이터 행 모음을 사용하여 구현 된 경우 부울 플래그의 효과를 지역화 할 수 있지만 더 많은 플래그가 필요합니다. 쿼드 트리에서는 루트 노드에 대해 빈 플래그를 설정하고 행 배열에서 각 행에 대한 플래그를 설정합니다.
“대형 2D 배열을 반복적으로 0으로 설정하려는 이유”라는 질문으로 이어지는 것은 무엇입니까? 어레이의 용도는 무엇입니까? 배열을 0으로 만들 필요가 없도록 코드를 변경하는 방법이 있습니까?
예를 들어 다음과 같은 경우 :
clear array
for each set of data
for each element in data set
array += element
즉, 누적 버퍼에 사용하고 다음과 같이 변경하면 성능이 향상됩니다.
for set 0 and set 1
for each element in each set
array = element1 + element2
for remaining data sets
for each element in data set
array += element
이것은 배열을 지울 필요가 없지만 여전히 작동합니다. 그리고 그것은 어레이를 지우는 것보다 훨씬 빠를 것입니다. 내가 말했듯이 가장 빠른 방법은 처음부터하지 않는 것입니다.
답변
당신이 정말로 속도에 집착한다면 (이동성에 그다지 그다지 중요하지 않음) 이것을 수행하는 가장 빠른 방법은 SIMD 벡터 내장을 사용하는 것입니다. 예를 들어 Intel CPU에서는 다음 SSE2 명령어를 사용할 수 있습니다.
__m128i _mm_setzero_si128 (); // Create a quadword with a value of 0.
void _mm_storeu_si128 (__m128i *p, __m128i a); // Write a quadword to the specified address.
각 저장 명령은 한 번의 히트에서 4 개의 32 비트 정수를 0으로 설정합니다.
p는 16 바이트로 정렬되어야하지만이 제한은 캐시에 도움이되기 때문에 속도에도 좋습니다. 다른 제한은 p가 16 바이트의 배수 인 할당 크기를 가리켜 야한다는 것입니다.하지만 루프를 쉽게 풀 수 있기 때문에 이것 역시 멋집니다.
이것을 루프에 넣고 루프를 몇 번 풀면 엄청나게 빠른 이니셜 라이저가 생깁니다.
// Assumes int is 32-bits.
const int mr = roundUpToNearestMultiple(m, 4); // This isn't the optimal modification of m and n, but done this way here for clarity.
const int nr = roundUpToNearestMultiple(n, 4);
int i = 0;
int array[mr][nr] __attribute__ ((aligned (16))); // GCC directive.
__m128i* px = (__m128i*)array;
const int incr = s >> 2; // Unroll it 4 times.
const __m128i zero128 = _mm_setzero_si128();
for(i = 0; i < s; i += incr)
{
_mm_storeu_si128(px++, zero128);
_mm_storeu_si128(px++, zero128);
_mm_storeu_si128(px++, zero128);
_mm_storeu_si128(px++, zero128);
}
_mm_storeu
캐시를 우회 하는 변형도 있습니다 (즉, 어레이를 0으로 설정해도 캐시가 오염되지 않음). 일부 상황에서 2 차 성능 이점을 제공 할 수 있습니다.
SSE2 참조는 여기를 참조하십시오 : http://msdn.microsoft.com/en-us/library/kcwz153a(v=vs.80).aspx
답변
로 배열을 초기화하는 malloc
경우 calloc
대신 사용하십시오. 무료로 어레이를 제로화합니다. (분명히 memset과 동일한 성능이며 코드가 적습니다.)
답변
int array[N][M] = {0};
… 적어도 GCC 4.8에서는.
답변
2D 배열은 어떻게 선언 되었습니까?
다음과 같은 경우 :
int arr[20][30];
다음을 수행하여 제로화 할 수 있습니다.
memset(arr, sizeof(int)*20*30);