Я хочу неоднократно обнулить большой 2-й массив в C. Это - то, что я делаю в данный момент:
// 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 массивы. Когда я, которого обнуляет printf, который содержание 2D массива, первая строка, но затем я получил загрузку случайных больших количеств и она отказывает.
memset(array, 0, sizeof(array[0][0]) * m * n);
Где m
и n
- ширина и высота двумерного массива (в вашем примере у вас квадратный двумерный массив, поэтому m == n
).
Как был объявлен ваш 2D-массив?
Если это что-то вроде:
int arr[20][30];
Вы можете обнулить его, выполнив:
memset(arr, sizeof(int)*20*30);
Ну, самый быстрый способ сделать это - вообще этого не делать.
Звучит странно, я знаю, вот какой-то псевдокод:
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-массив был реализован с использованием, скажем, дерева квадратов (не динамического разума) или набора строк данных, то вы можете локализовать эффект логического флага, но вам понадобится больше флагов. В дереве квадратов просто установите пустой флаг для корневого узла, в массиве строк просто установите флаг для каждой строки.
Это приводит к вопросу «почему вы хотите многократно обнулять большой двумерный массив»? Для чего используется массив? Есть ли способ изменить код, чтобы массив не нуждался в обнулении?
Например, если у вас есть:
clear array
for each set of data
for each element in data set
array += element
то есть использовать его для буфера накопления, а затем изменить его таким образом, чтобы повысить производительность no end:
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
Это не требует очистки массива, но все равно работает. И это будет намного быстрее, чем очистка массива. Как я уже сказал, самый быстрый способ - это вообще не делать этого.
Это происходит потому, что sizeof (array) дает вам размер выделения для объекта, на который указывает array . ( array - это просто указатель на первую строку вашего многомерного массива). Однако вы выделили j массивов размером i . Следовательно, вам нужно умножить размер одной строки, возвращаемой функцией sizeof (array), на количество выделенных вами строк, например :
bzero(array, sizeof(array) * j);
. Также обратите внимание, что sizeof (array) будет работать только для статически выделенных массивов. Для динамически распределенного массива вы должны написать
size_t arrayByteSize = sizeof(int) * i * j;
int *array = malloc(array2dByteSite);
bzero(array, arrayByteSize);
Я думаю, что самый быстрый способ сделать это вручную - это выполнить код. Вы можете сравнить его скорость с функцией memset, но она не должна быть медленнее.
(изменить тип указателей ptr и ptr1, если тип вашего массива отличается от int)
#define SIZE_X 100
#define SIZE_Y 100
int *ptr, *ptr1;
ptr = &array[0][0];
ptr1 = ptr + SIZE_X*SIZE_Y*sizeof(array[0][0]);
while (ptr
Если array
действительно массив, то вы можете "обнулить" его с помощью:
memset(array, 0, sizeof array);
Но есть два момента, которые вы должны знать:
array
действительно "двумерный массив", т.е., был объявлен 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()
размер arr[0]
является размером массива arr[0]
, который представляет собой "массив [5] из int
". Это не размер int *
, потому что "распад" происходит только на первом уровне, и поэтому нам нужно объявить f()
как принимающий указатель на массив правильного размера.
Итак, как я уже сказал, то, что вы делали изначально, будет работать, только если выполняются два вышеуказанных условия. Если нет, вам нужно будет сделать то, что сказали другие:
memset(array, 0, m*n*sizeof array[0][0]);
Наконец, memset()
и for
цикл, который вы опубликовали, не эквивалентны в строгом смысле. Могут существовать (и существовали) компиляторы, в которых "все биты нулевые" не равны нулю для определенных типов, таких как указатели и значения с плавающей точкой. Однако я сомневаюсь, что вам стоит беспокоиться об этом.
Если вы инициализируете массив с помощью malloc
, используйте вместо этого calloc
; это обнулит ваш массив бесплатно. (Совершенство очевидно такое же, как и у memset, просто меньше кода для вас)