matrices - matriz dinamica en c
Diferencia entre el tipo de matriz y la matriz asignada con malloc (9)
Aquí hay varias piezas diferentes en juego.
El primero es la diferencia entre declarar una matriz como
int array[n];
y
int* array = malloc(n * sizeof(int));
En la primera versión, declaras un objeto con duración de almacenamiento automático. Esto significa que la matriz vive solo mientras exista la función que la llama. En la segunda versión, obtiene memoria con duración de almacenamiento dinámico, lo que significa que existirá hasta que se desasigne explícitamente de forma free
.
La razón por la que la segunda versión funciona aquí es un detalle de implementación de cómo C generalmente se compila. Normalmente, la memoria C se divide en varias regiones, incluida la pila (para llamadas a funciones y variables locales) y el montón (para objetos malloc
). La pila generalmente tiene un tamaño mucho más pequeño que el montón; por lo general, es algo así como 8 MB. Como resultado, si intenta asignar una gran matriz con
int array[n];
Entonces puede exceder el espacio de almacenamiento de la pila, causando la segfault. Por otro lado, el montón generalmente tiene un gran tamaño (por ejemplo, tanto espacio como libre en el sistema), por lo que el malloc
un objeto grande no causará un error de falta de memoria.
En general, tenga cuidado con las matrices de longitud variable en C. Pueden exceder fácilmente el tamaño de la pila. Prefiere malloc
menos que sepas que el tamaño es pequeño o que realmente solo quieres la matriz por un corto período de tiempo.
¡Espero que esto ayude!
Hoy estaba ayudando a un amigo mío con un código C, y he encontrado un comportamiento extraño que no podía explicarle por qué estaba sucediendo. Teníamos un archivo TSV con una lista de enteros, con un int cada línea. La primera línea era la cantidad de líneas que tenía la lista.
También teníamos un archivo ac con un "archivo de lectura" muy simple. La primera línea se leyó a n, el número de líneas, luego hubo una inicialización de:
int list[n]
y finalmente un bucle for de n con fscanf.
Para pequeñas n (hasta ~ 100.000), todo estaba bien. Sin embargo, hemos encontrado que cuando n era grande (10 ^ 6), se producía un segfault.
Finalmente, cambiamos la inicialización de la lista a
int *list = malloc(n*sizeof(int))
y todo cuando está bien, incluso con n muy grande.
¿Alguien puede explicar por qué ocurrió esto? ¿Qué estaba causando segfault with int list [n], que se detuvo cuando empezamos a usar list = malloc (n * sizeof (int))?
Cuando asigna utilizando un malloc
, la memoria se asigna desde el montón y no desde la pila, que tiene un tamaño mucho más limitado.
Esta declaración asigna memoria en la pila
int list[n]
malloc asigna en el montón.
El tamaño de pila suele ser más pequeño que el montón, por lo que si asigna demasiada memoria a la pila, obtiene un .
Ver también esta respuesta para más información
Si está en Linux, puede establecer ulimit -s a un valor mayor y esto también podría funcionar para la asignación de la pila. Cuando asigna memoria en la pila, esa memoria permanece hasta el final de la ejecución de su función. Si asigna memoria en heap (utilizando malloc), puede liberar la memoria cuando lo desee (incluso antes de que finalice la ejecución de su función).
Generalmente, heap debe usarse para asignaciones de memoria grandes.
Suponiendo que tiene una implementación típica en su implementación, lo más probable es que:
int list[n]
lista asignada en tu pila, donde como:
int *list = malloc(n*sizeof(int))
memoria asignada en tu montón.
En el caso de una pila, normalmente existe un límite de la capacidad de crecimiento (si es que pueden crecer). En el caso de un montón, todavía hay un límite, pero eso tiende a ser en gran medida y (en general) restringido por su espacio de direcciones RAM + swap + que normalmente es al menos un orden de magnitud mayor, si no más.
int list [n] almacena los datos en la pila, mientras que malloc los almacena en el montón.
La pila es limitada y no hay mucho espacio, mientras que el montón es mucho más grande.
int list[n]
es un VLA, que asigna en la pila en lugar de en el montón. No tiene que liberarlo (se libera automáticamente al final de la llamada a la función) y se asigna rápidamente, pero el espacio de almacenamiento es muy limitado, como ha descubierto. Debe asignar valores más grandes en el montón.
int array[n];
Es un ejemplo de matriz asignada estáticamente y en el momento de la compilación se conocerá el tamaño de la matriz. Y la matriz se asignará en la pila.
int *array(malloc(sizeof(int)*n);
Es un ejemplo de matriz asignada dinámicamente y el usuario conocerá el tamaño de la matriz en el momento de la ejecución. Y la matriz se asignará en el montón.
int list[n]
Asigna espacio para n
enteros en la pila , que generalmente es bastante pequeño. El uso de memoria en la pila es mucho más rápido que la alternativa, pero es bastante pequeño y es fácil desbordar la pila (es decir, asignar demasiada memoria) si hace cosas como asignar matrices enormes o hacer recursiones demasiado profundas. No tiene que desasignar manualmente la memoria asignada de esta manera, sino que lo hace el compilador cuando la matriz se sale del alcance.
malloc
por otro lado, asigna espacio en el montón , que suele ser muy grande en comparación con la pila. Tendrá que asignar una cantidad mucho mayor de memoria en el montón para agotarlo, pero es mucho más lento asignar memoria en el montón que en la pila, y debe desasignarlo manualmente de forma free
cuando haya terminado de usar eso.