Quiero poner a cero repetidamente una gran matriz 2d en C. Esto es lo que hago en este momento:
// 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;
}
}
Intenté usar memset:
memset(array, 0, sizeof(array))
Pero esto solo funciona para matrices 1D. Cuando imprimo el contenido de la matriz 2D, la primera fila son ceros, pero luego obtuve una carga de números grandes aleatorios y se bloquea.
memset
, porque mencionaste que también se bloquea por poner a cero solo una fila.int d0=10, d1=20; int arr[d0][d1]
ymemset(arr, 0, sizeof arr);
funcionó como se esperaba (gcc 3.4.6, compilado con-std=c99 -Wall
banderas). Me doy cuenta de que "funciona en mi máquina" significa sentadilla, peromemset(arr, 0, sizeof arr);
debería haber funcionado.sizeof arr
debe devolver el número de bytes utilizados por toda la matriz (d0 * d1 * sizeof (int)).sizeof array[0] * m * n
no le dará el tamaño correcto de la matriz.int array[][10]
, entonces,sizeof(array) == sizeof(int*)
dado que no se conoce el tamaño de la primera dimensión. El OP no especificó cómo se obtuvo la matriz.Si
array
es realmente una matriz, entonces puede "ponerla a cero" con:Pero hay dos puntos que debes conocer:
array
es realmente una "matriz bidimensional", es decir, se declaróT array[M][N];
para algún tipoT
.array
fue declarado. Si lo pasa a una función, entonces el nombre searray
convierte en un puntero ysizeof
no le dará el tamaño de la matriz.Hagamos un experimento:
En mi máquina, se imprime lo anterior:
Aunque
arr
es una matriz, se convierte en un puntero a su primer elemento cuando se pasa af()
, y por lo tanto los tamaños impresosf()
son "incorrectos". Además, enf()
el tamaño dearr[0]
es el tamaño de la matrizarr[0]
, que es una "matriz [5] deint
". No es del tamaño de unint *
, porque el "decaimiento" solo ocurre en el primer nivel, y es por eso que necesitamos declararf()
como tomando un puntero a un arreglo del tamaño correcto.Entonces, como dije, lo que estaba haciendo originalmente solo funcionará si se cumplen las dos condiciones anteriores. De lo contrario, deberá hacer lo que otros han dicho:
Finalmente,
memset()
y elfor
bucle que publicaste no son equivalentes en sentido estricto. Podría haber (y ha habido) compiladores donde "todos los bits cero" no es igual a cero para ciertos tipos, como punteros y valores de coma flotante. Sin embargo, dudo que tengas que preocuparte por eso.fuente
memset(array, 0, n*n*sizeof array[0][0]);
¿Supongo que te refieres a quem*n
non*n
?memset
funciona a nivel de bytes (char). Dado que1
o2
no tienen los mismos bytes en la representación subyacente, no puede hacer eso conmemset
.int
en su sistema hay 4 bytes" en algún lugar antes del ejemplo de trabajo mínimo, para que el lector pueda calcular fácilmente las sumas.Bueno, la forma más rápida de hacerlo es no hacerlo en absoluto.
Suena extraño, lo sé, aquí hay un pseudocódigo:
En realidad, todavía está borrando la matriz, pero solo cuando se escribe algo en la matriz. Esto no es una gran ventaja aquí. Sin embargo, si la matriz 2D se implementó usando, digamos, un árbol cuádruple (no una mente dinámica), o una colección de filas de datos, entonces puede localizar el efecto de la bandera booleana, pero necesitaría más banderas. En el árbol cuádruple, simplemente configure la bandera vacía para el nodo raíz, en la matriz de filas simplemente configure la bandera para cada fila.
Lo que lleva a la pregunta "¿por qué quiere poner a cero repetidamente una matriz 2d grande"? ¿Para qué se utiliza la matriz? ¿Hay alguna forma de cambiar el código para que la matriz no necesite puesta a cero?
Por ejemplo, si tuvieras:
es decir, utilícelo para un búfer de acumulación, luego cambiarlo de esta manera mejoraría el rendimiento sin fin:
Esto no requiere que se borre la matriz, pero aún funciona. Y eso será mucho más rápido que borrar la matriz. Como dije, la forma más rápida es no hacerlo en primer lugar.
fuente
Si está realmente obsesionado con la velocidad (y no tanto con la portabilidad), creo que la forma más rápida de hacerlo sería usar los intrínsecos vectoriales SIMD. Por ejemplo, en CPU Intel, puede usar estas instrucciones SSE2:
Cada instrucción de almacenamiento establecerá cuatro entradas de 32 bits en cero en un solo golpe.
p debe estar alineado con 16 bytes, pero esta restricción también es buena para la velocidad porque ayudará a la caché. La otra restricción es que p debe apuntar a un tamaño de asignación que sea un múltiplo de 16 bytes, pero esto también es genial porque nos permite desenrollar el ciclo fácilmente.
Haga esto en un bucle y desenrolle el bucle unas cuantas veces, y tendrá un inicializador increíblemente rápido:
También hay una variante de
_mm_storeu
que evita la caché (es decir, poner a cero la matriz no contaminará la caché) lo que podría brindarle algunos beneficios secundarios de rendimiento en algunas circunstancias.Consulte aquí para obtener una referencia de SSE2: http://msdn.microsoft.com/en-us/library/kcwz153a(v=vs.80).aspx
fuente
Si inicializa la matriz con
malloc
, usecalloc
en su lugar; pondrá a cero su matriz de forma gratuita. (Obviamente, el mismo rendimiento que memset, solo que menos código para usted).fuente
int array[N][M] = {0};
... al menos en GCC 4.8.
fuente
¿Cómo se declaró su matriz 2D?
Si es algo como:
Puede ponerlo a cero haciendo:
fuente
memset(a, 0, sizeof(char)*10*10);
funciona bien para mí. , ¿Cómo sucede?Utilice calloc en lugar de malloc. calloc iniciará todos los campos a 0.
int * a = (int *) calloc (n, tamaño de (int));
// todas las celdas de a se han inicializado a 0
fuente
Creo que la forma más rápida de hacerlo a mano es siguiendo el código. Puede comparar su velocidad con la función de memset, pero no debería ser más lenta.
(cambie el tipo de punteros ptr y ptr1 si su tipo de matriz es diferente de int)
fuente
memset
para los tipos de caracteres.fuente
Puedes probar esto
fuente
Esto sucede porque sizeof (matriz) le da el tamaño de asignación del objeto al que apunta la matriz . (la matriz es solo un puntero a la primera fila de su matriz multidimensional). Sin embargo, asignó j matrices de tamaño i . En consecuencia, debe multiplicar el tamaño de una fila, que se devuelve por sizeof (matriz) con el número de filas que asignó, por ejemplo:
También tenga en cuenta que sizeof (matriz) solo funcionará para matrices asignadas estáticamente. Para una matriz asignada dinámicamente, escribiría
fuente
sizeof
operador,array
no es un puntero (si se declaró una matriz). Vea mi respuesta como ejemplo.