Pregunta

int main()
{
   char myString = NULL;
   realloc(&myString, 5);
   strncpy((char *)&myString, "test", 5);
}

Parece funcionar bien, pero todavía estoy un poco confundido acerca de stack vs heap. ¿Esto está permitido? Si está permitido, ¿necesita myString liberarse manualmente o se liberará cuando esté fuera de alcance?


Editar: gracias por las respuestas, así que supongo que esto es igualmente ilegal

//I want the code to change myString to "tests"
char myString[5] = "test";
realloc(&myString, strlen(myString)+2);
myString[4] = 's';
myString[5] = '\0';
¿Fue útil?

Solución

No, esto está completamente mal. realloc solo debe usarse para reasignar la memoria asignada por malloc, lo que está haciendo funciona solo por accidente y eventualmente se bloqueará horriblemente

char *myString = malloc(x);
myString = realloc(myString,y);
free(myString)

Sin embargo, es mejor usar new y delete, e incluso mejor usando std :: string.

Otros consejos

Algunos problemas con el código que publicó:

  • Sí, necesita liberar todo lo que asigna con malloc y realloc, y las otras funciones de asignación de memoria de estilo C relacionadas.
  • Creo que querías tener char * myString, no char. Pasar la dirección de algo en la pila (su char) es completamente incorrecto.
  • Debe inicializar su puntero de caracteres myString a NULL antes de usarlo en realloc.
  • Debería pasar 4 a strncpy, no 5, si tuviera una cadena más grande sobrescribiría la memoria.
  • Debería estar liberando el búfer que creó en su ejemplo
  • Debería verificar el valor de retorno de su llamada realloc. realloc ()
  

[Respecto al valor de retorno de realloc:] Al completar con éxito un tamaño   no es igual a 0, realloc () devuelve un   puntero al (posiblemente movido)   espacio asignado Si el tamaño es 0, bien   un puntero nulo o un puntero único   que se puede pasar con éxito a   Se devuelve free (). Si no hay   suficiente memoria disponible, realloc ()   devuelve un puntero nulo y establece errno   a [ENOMEM].

  • re-alloc funcionará como malloc cuando pase NULL:
  

Si ptr es un puntero nulo, realloc ()   se comporta como malloc () para el   tamaño especificado.

Una forma más de C ++ de hacerlo:

Sin embargo, etiquetó esto como C ++, y es más seguro usar el nuevo operador de C ++. Aunque el nuevo operador no permite la reasignación, funcionará para las asignaciones y para reutilizar las memorias intermedias existentes (ubicación nueva).

char *myString = new char[5];
strncpy(myString, "test", 4); 
//...
delete[] myString;

o incluso:

#include <string>

//...

std::string str = "test";

Fuente de las 2 citas principales

Esto no debería funcionar. Estás reasignando algo que no fue mallogado en primer lugar. Y no, no se liberará cuando salga del alcance: cuando use malloc o realloc, todo depende de usted.

Actualización: su edición no cambia nada, todavía está tratando de reasignar algo que no estaba mal colocado en primer lugar. Además, no puede ignorar el valor de retorno de realloc: si realloc tiene que mover la memoria a otro lugar, lo encontrará en el retorno. En otras palabras:

char* ptr = malloc(4);
ptr = realloc(ptr, 5);

Después de realloc, ptr podría estar apuntando a un lugar completamente diferente en la memoria, y continuar usando el valor original de ptr podría dejarlo usando la memoria que se ha liberado y que no es tan grande como cree que es.

¡ESTO ES PELIGROSO! Esto corromperá tu pila. Si tuviera que reasignar algo en la pila de una función que luego regresó a main (), en realidad terminaría sobrescribiendo el marco de la pila y regresando a otro lugar que no sea main (). ESTE ES UN AGUJERO DE SEGURIDAD POTENCIAL.

Intenta ejecutar lo siguiente. Si se bloquea en realloc, tienes suerte. Puede causar daños graves con algo como memcpy (& amp; myString).

int dostuff();

int main()
{
        dostuff();
        return 0;
}

int dostuff()
{
        char myString = NULL;
        realloc(&myString, 5);
        strncpy((char *)&myString, "test", 5);
        return 0;
}

Esto es lo que nunca debes hacer. Intentar liberar () o realloc () una variable de pila puede conducir a un comportamiento indefinido que incluye (pero no se limita a) pila corrupta (que conduce a un flujo de control impredecible), estructuras de servicio de montón corruptas, memoria de usuario corrupta. Tienes suerte si el programa simplemente falla con un AV. Puede funcionar en algunos casos, pero nunca debe intentar hacerlo.

Regla de oro: solo devuelve la memoria al administrador de memoria en el que se asignó. En este caso, no intente devolver la variable de pila al montón de tiempo de ejecución.

Su programa es sintácticamente válido C ++, pero producirá un comportamiento indefinido porque pasa la dirección de un objeto de pila al asignador de montón. Por lo general, esto significa que su programa se bloqueará cuando se ejecute.

La pila y el montón son dos áreas distintas de memoria asignadas al proceso que ejecuta su programa. La pila crece a medida que ingresa una función para contener sus argumentos y variables locales, y se reduce automáticamente cuando regresa de la función. El montón, por otro lado, es una región de dirección separada donde se puede obtener memoria bajo demanda, y debe liberarse explícitamente cuando ya no sea necesaria.

Si la dirección de una variable local se pasa a realloc (), puede intentar liberar su memoria y asignarla a otro lugar. Dado que la dirección no es del montón, y realloc () opera en el montón, esto fallará. Lo más probable es que realloc () detecte que la dirección no es del montón y cancele el programa.


Aparte de esto, el programa de ejemplo contiene algunos errores lógicos.


char myString = NULL;

Usted declara una variable para contener un carácter, no una cadena. Una cadena de estilo C tiene el tipo char * , es decir, un puntero a char.

Además, al carácter se le asigna NULL , la dirección cero que se asigna convencionalmente a punteros no válidos. Esto se compila porque el preprocesador reemplaza NULL por el literal 0 . Realmente, almacena un byte cero en el carácter, que es, también por convención, el terminador de una cadena de estilo C.


realloc(&myString, 5);

Como se mencionó anteriormente, esto es ilegal porque pasa la dirección de un objeto de pila al asignador del montón. Este problema permanece en su segundo ejemplo de código.

Además, descarta el valor de retorno. realloc () devuelve la dirección donde se asignó la nueva memoria. Puede que no sea la misma dirección que antes. Incluso puede ser NULL, que es la forma de realloc () de decirle que se quedó sin memoria.


strncpy((char *)&myString, "test", 5);

Esto es correcto, pero el reparto es redundante.


Aquí hay una versión más correcta de su programa:


#include <stdlib.h>
#include <string.h>

int main()
{
   /* allocate space for, say, one character + terminator */
   char* myString = (char*) malloc(2);

   /* some code using myString omitted */

   /* get more space */
   myString = (char*) realloc(myString, 5);

   /* write to the string */
   strncpy(myString, "test", 5);

   /* free the memory */
   free(myString);

   return 0;
}

En C ++, es mejor evitar completamente realloc (). Por ejemplo, podría usar algo como lo siguiente:


#include <string>

int main()
{
   std::string myString;

   /* some code using myString */

   myString = "test";

   return 0;
}

No tiene que liberar myString ya que está en la pila (que se libera " al salir del alcance).

realloc es ilegal aquí, la dirección debe ser NULL o una dirección devuelta por una llamada anterior a realloc , malloc o calloc .

Cada variable que declaras está en la pila, incluso un puntero:

int * x;

¡La variable x está en la pila! Es de tipo puntero y contiene una dirección.

x = (int *) malloc (sizeof (int));

asigna la dirección devuelta por malloc a la variable x! ¡El contenido de x es una dirección de memoria!

El problema con lo que estás haciendo es que estás jugando con algo que no es una variable. Definió myString como un carácter y, por lo tanto, está tratando de cambiar su dirección. Eso es malo.

Se supone que la función realloc () no cambia nada de lo que se le pasa. Lleva un puntero a alguna memoria en el montón (o el puntero nulo, si ya no hay nada asignado) y devuelve un puntero a alguna memoria en el montón.

Por lo tanto, proporciona un puntero nulo o un puntero a algo asignado por malloc () o realloc () o calloc (), y almacena el puntero devuelto.

Algo así

char * myString = NULL;
myString = realloc(myString, 5);

funcionará, pero querrás liberar () myString.

En C ++, sin embargo, use std :: string.

En respuesta a su segundo ejemplo de código:

Sí, esto también es ilegal. myString no está asignado con malloc (o calloc), por lo que no puede reasignarse con realloc ni liberarse de forma gratuita.

Además, que realloc no toma un puntero a un puntero como primer argumento. Toma un puntero a la memoria asignada y devuelve otro puntero (posiblemente diferente). En su lugar, escriba la llamada así:

myString = realloc(myString, strlen(myString)+2);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top