2010-07-17 20 views
5

¿Cuál es la diferencia entre esto:C++: definición de matriz local frente a una llamada malloc

somefunction() { 
    ... 
    char *output; 
    output = (char *) malloc((len * 2) + 1); 
    ... 
} 

y esto:

somefunction() { 
    ... 
    char output[(len * 2) + 1]; 
    ... 
} 

Cuando uno es más apropiado que el otro?

gracias por todas sus respuestas. aquí hay un resumen:

  1. ex. 1 es la asignación de pila
  2. ej. 2 es la asignación de pila
  3. hay una limitación de tamaño en la pila, lo utilizan para asignaciones más pequeñas
  4. tienes que asignación del montón libre, o que se escape
  5. la asignación de pila no es accesible una vez que la función termina
  6. la asignación del montón es accesible hasta que lo libere (o la aplicación termina)
  7. VLA no es parte de C++ estándar

correcciones son bienvenidos.

aquí es una explicación de la diferencia entre el montón vs pila:
What and where are the stack and heap?

+0

Debería consultar su libro en C++. Si no tiene un libro en C++, le recomiendo que obtenga uno de los textos para principiantes que figuran en [La guía y la lista completa de libros de C++] (http://stackoverflow.com/questions/388242/the-definitive-c-book -guía y lista). –

+4

Además, la pregunta depende completamente de cómo se define 'len'; si no es una constante, entonces el segundo ejemplo de código está mal formado C++. –

+0

len es un int y está asignado al resultado de strlen dentro de la función. – Gush

Respuesta

5

Usa los locales cuando solo tienes una pequeña cantidad de datos, y no vas a utilizar los datos fuera del alcance de la función en la que lo has declarado. Si vas a pasar los datos, usa malloc.

Las variables locales se mantienen en la pila, que es mucho más limitada que el montón, donde van las matrices asignadas con malloc. Normalmente voy por cualquier cosa> 16 bytes que se pongan en el montón, pero tienes un poco más de flexibilidad que eso. Simplemente no asigne locales en el rango de tamaño kb/mb; pertenecen al montón.

+2

+1 por mencionar las limitaciones de tamaño de la pila, pero creo que 16 bytes son un poco bajos. ¿No es el tamaño de pila predeterminado en la mayoría de las plataformas en megabytes (por lo que las variables de varios KB deberían estar bien en la mayoría de los casos)? –

+0

Sí, pero cuando asigna en la pila, también debe considerar la duración de los datos así como su tamaño. Quise decir 16 bytes para valores cuya vida útil puede no ser conocida. Puede asignar varios kb en la pila, luego bifurcar en otra función, que también asigna muchos kb, y así sucesivamente, puede llenarse rápidamente. (Se discutió esto más en la respuesta de StackedCrooked). –

+3

Dado que la pregunta es sobre C++, me opongo firmemente a la recomendación de utilizar malloc. En C, usa malloc. En C++, usa nuevo. –

6

El primer recuerdo asigna en el montón. Tienes que recordar liberar la memoria, o se perderá. Esto es apropiado si la memoria necesita usarse fuera de la función, o si necesita asignar una gran cantidad de memoria.

El segundo asigna memoria en la pila. Se recuperará automáticamente cuando la función regrese. Esto es lo más conveniente si no necesita devolver la memoria a su interlocutor.

+1

Por otro lado, no desea poner demasiado en la pila, porque no es tan grande como el montón. Entonces, 'int data [10]' está bien, pero no contaría con 'int data [10000]' funcionando. – zvone

5

El primer ejemplo asigna un bloque de almacenamiento del montón. El segundo asigna almacenamiento de la pila. La diferencia se vuelve visible cuando devuelve salida de alguna función(). El almacenamiento asignado dinámicamente todavía está disponible para su uso, pero el almacenamiento basado en la pila en el segundo ejemplo es, um, en ninguna parte. Todavía puede escribir en este almacenamiento y leerlo por un tiempo, hasta la próxima vez que llame a una función, momento en el cual el almacenamiento se sobrescribirá aleatoriamente con direcciones de retorno, argumentos, etc.

También hay muchas otras cosas raras con el código en esta pregunta. En primer lugar, este es un programa C++, te gustaría usar nueva en lugar de malloc() de modo que dirías

output = new char[len+1]; 

Y lo que es con la len * 2 + 1 de todos modos?Tal vez esto sea algo especial en tu código, pero supongo que quieres asignar caracteres Unicode o caracteres multibyte. Si es unicode, la terminación nula requiere dos bytes, así como cada carácter, y char es del tipo incorrecto, siendo bytes de 8 bits en la mayoría de los compiladores. Si es multibyte, entonces oye, todas las apuestas están apagadas.

+1

1 para nuevos vs malloc – bstpierre

+0

no sé si lo que estoy haciendo es correcto - pero se deriva de la documentación para PQescapeStringConn - " 'a' deberá apuntar a un búfer que es capaz de mantener al menos uno más bytes de dos veces el valor de la longitud" desde aquí: http://www.postgresql.org/docs/7.3/static/libpq-exec.html – Gush

3

primer lugar algunos términos:

  • La primera muestra se llama asignación de montón.
  • La segunda muestra se llama Asignación de pila.

La regla general es: asignar en la pila, a menos que:

  1. El tamaño requerido de la matriz es desconocido en tiempo de compilación.
  2. El tamaño requerido excede el 10% del tamaño total de la pila. El tamaño de pila predeterminado en Windows y Linux suele ser de 1 o 2 MB. Entonces su arreglo local no debe exceder 100,000 bytes.
+1

creo que esas reglas generales son un poco débil. Por ejemplo, podría asignar 10% de mi pila en main(), y luego llamar a alguna otra función (que a su vez llamará más y más, cada una llenando la pila). No voy a poder liberar ese espacio hasta que se completen todas mis funciones más profundas (esencialmente el final del programa en este caso). Mi programa tiene automáticamente un 10% menos de espacio en la pila. Creo que la regla del 10% debería restringirse solo a las funciones ** puras ". –

+1

@Mark H: Tiene razón en que la regla del 10% no debe asignarse en main, y ciertamente no en el código de reentrada. Sin embargo, no veo cómo las funciones puras serían más seguras contra el desbordamiento de la pila que las funciones no puras. – StackedCrooked

+1

Una función pura no llamará a otras funciones (a menos que ellas mismas sean puras), pero generalmente realizarán algún algoritmo y regresarán de inmediato. Cualquier variable local que asigne en ellos tendrá una vida corta, que es como debería ser la pila. Las variables que tienen vidas más largas (como el ejemplo anterior) deberían ir en el montón. –

1

Marcó su pregunta con C++ y C, pero la segunda solución no está permitida en C++. Las matrices de longitud variable solo están permitidas en C (99).

Si supusiera que 'len' es una constante, ambos funcionarán.

malloc() (y C++ 's' nuevo ') asigna la memoria en el montón, lo que significa que tiene que liberar() (o si asignó con' nuevo ',' eliminar ') el búfer, o la memoria nunca ser reclamado (fuga).

Este último asigna la matriz en la pila y desaparecerá cuando se salga del alcance. Esto significa que no puede devolver punteros al búfer fuera del alcance asignado.

El primero es útil cuando quiere pasar el bloque de memoria (pero en C++, se gestiona mejor con una clase RAII, no manualmente), mientras que el último es mejor para arreglos pequeños de tamaño fijo que solo necesitan existir en un ámbito.

Por último, se puede marcar la matriz de otro modo apilar-asignado con 'estático' para llevarlo fuera de la pila y en una sección de datos global:

static char output[(len * 2) + 1]; 

Esto le permite volver punteros a la memoria intermedia fuera del su alcance, sin embargo, todas las llamadas a dicha función se referirán a la misma pieza de datos globales, por lo tanto, no la use si necesita un bloque único de memoria cada vez.

Por último, no use malloc en C++ a menos que tenga una buena razón (es decir, realloc). Use 'nuevo' en su lugar, y el 'eliminar' que lo acompaña.

+0

de http: //gcc.gnu.org/onlinedocs/gcc/Variable-Length.html Las matrices automáticas de longitud variable están permitidas en ISO C99 y, como extensión, GCC las acepta en modo C90 y en C++. Supongo que es por eso que compila y funciona para mí usando gcc. Podría creer que no es C++ según el estándar o la definición adecuada del idioma al que te refieres. ¿Debo eliminar la etiqueta C++? – Gush

+0

Simplemente me preguntaba qué estabas usando, pero para que asuma C++, pensé que te advertiría que los VLA no son parte de C++ estándar. –

+0

bien. yo no sabía eso y es relevante – Gush

Cuestiones relacionadas