Se que si yo hago esto:
char *cadena = "Hola";
Se reserva una determinada cantidad de bytes en alguna parte de la memoria, en este caso, 4 bytes, por que son 4 caracteres.
Pero si ahora yo hago esto:
char *cadena = "Sol";
Se reservara 3 bytes mas para esta cadena, y acá mi pregunta:
¿Que pasa con los otros 4 bytes que reserve para la cadena "Hola", se reemplaza por estos?
Supongamos que se reemplaza, entonces, quedaría un byte libre, con la letra "a", ¿como haría para liberar ese espacio inútil? Ya que esta cadena solo ocupa 3 letras y sobraría 1, que había reservado anteriormente.
Espero me haya dado a explicar.
Mil gracias y espero me disculpen por molestar tanto, estoy estudiando C++ y me surgieron un montón de dudas y no las encontré en la web :-\
No puedes declarar dos variables con el mismo nombre en la misma función :xD
Si hubieras probado te habrías dado cuenta.
A parte de lo que dice PabloPbl, con la primera cadena se reserva espacio para CINCO caracteres. El último carácter indica el fin de la cadena (equivale a 0). Por ejemplo, la declaración
char cadena[] = "Hola";
equivale a la declaración
char cadena[] = {'H', 'o', 'l', 'a', '\0'};
Si no se pusiera ese carácter, no sabríamos el final de la cadena.
Hola Pablo, cuánto tiempo sin hablar.
Citar¿Que pasa con los otros 4 bytes que reserve para la cadena "Hola", se reemplaza por estos?
cadena al principio apunta a "Hola" en donde sea que esté el "H" pues allí es donde está apuntando, siempre que crees una cadena así como lo estás haciendo siempre se agrega un '\0' al final de la cadena( como ya te han dicho), es como si le dijeras al compilador que allí es donde termina la cadena. Ahora cuando haces que cadena apunte a "Sol" entonces la cadena "Hola" seguirá existiendo en la computadora, el problema es que ya no vamos a saber en dónde( al menos que con otro puntero guardes la dirección a la que apuntaba cadena al principio, cuando apuntaba a "Hola"), como ahora cadena apunta a "Sol" y como "Hola" aún sigue existiendo en la computadora pues cadena tendrá otra dirección de memoria.
Entonces al hacer esas asignaciones terminas perdiendo los punteros( quién sabe en dónde irán a terminar), luego
creo que no se podrán liberar( el que se pierde, en este caso se pierde la dirección en donde se aloja "Hola", es como que un puntero no tiene memoria de las cosas a las que apunta, si lo cambias ya no se acordará de dónde apuntaba anteriormente).
Si es C++ entonces tienes a new y delete para manejar memoria dinámica, con eso como que te obligan a liberar la memoria cuando ya no lo estas utilizando, sino pues tienes que confiar a que la computadora libere la memoria( tipo java (xD)).
Ve fijándote en la dirección:
char* cadena = "Hola";
printf("Dirección %d ",&(*cadena));
cadena = "Sol";
printf("Dirección %d ",&(*cadena));
la dirección de cadena cambia. Luego también puedes guardar a "Hola" en otro puntero:
char* cadena = "Hola";
char* cadena2 = cadena; //salvamos a cadena antes de cambiar a lo que apunta
cadena = "Sol";
printf("%s",cadena);
printf("%s",cadena2);
Ahora cuando el programa termine se libera cadena y cadena2 tranquilamente.
Hola, muchas gracias a todos por la orientación, mas claro imposible ;-)
Pero tengo una duda mas :P
Si bien se que al hacer uso de esto, en una instrucción:
*puntero
Estoy obteniendo el valor de la dirección de memoria que se esta apuntando con el puntero.
Corrijanme si me equivoco.
Ahora quiero lograr obtener la dirección de memoria del valor que se esta apuntando con el puntero, me explico:
char *puntero = "Hola";
¿Como podría obtener la
dirección de memoria en donde se encuentra el caracter "H"?
He intentado hacerlo así:
char *puntero = "Hola";
cout << &(*puntero) << endl;
Pero lo único que hace es mostrarme la cadena entera, ¿por que pasa esto? ¿No se supone que me debería mostrar la dirección de memoria de lo que esta apuntando puntero?
CitarHola Pablo, cuánto tiempo sin hablar.
Hola Bro ;D si, anduve muy liado con los estudios(no me dejaban ni respirar). >:(
Pero bueno, espero poder volver al grupo así hacemos algo, si es que siguen :xD
Saludos.
Cast a void*:
char *cadena = "Hola";
cout << "Dirección: " << (void*)cadena << "\n";
Lo de arriba sólo funciona en C, disculpa por eso.
Al menos en C, para hacer esto:
char *cadena = "Hola";
Antes debes reservar memoria con alguna función como malloc o calloc:
char *cadena = (char *)calloc(5,sizeof(char));
strcpy(cadena,"Hola");
Y por último con strcpy asignar a cadena una frase.
Si tu haces:
char* cadena = "Hola";
No se reservan 4 bytes en alguna parte de la memoria. Se reservan 5 bytes(mas \0) en lo que se llama "stack" que es basicamente memoria eficiente y bastante limitada.
Cuando tu haces esto:
cadena = "Sol";
Que es lo que imagino que quisiste hacer, entonces has perdido la direccion donde esta "Hola" y tu puntero ahora apunta a "Sol" que son 4 bytes. Ahora, Sol no reemplaza a Hola de ninguna forma. Es decir, si crees que sucede esto "Sol\0a\0" te digo que eso no es lo que esta pasando, pero asumamos que es asi.
Entonces tenemos memoria que no nos sirve ocupando espacio y que debemos hacer para liberarla? Nada, porque fue reservada en el stack y la computadora maneja la memoria del stack por ti asi que no te preocupes por eso.
Ahora para elaborar un poco mas la respuesta de tu pregunta original y de paso responder la segunda tenemos que entender como se reserva la memoria en el stack. Supongamos que tenemos tu codigo original:
char* cadena = "Hola";
y la direccion de la memoria donde se encuentra H es 4195924 . Hola ocupa 5 bytes entonces el char final del string "Hola" esta en 4195929(que es \0). Ahora supongamos que tenemos:
cadena = "Sol";
Y la memoria es 4195949, entonces si haces printf("%s", cadena - 20);
lo que veas deberia ser Hola.
Para obtener la direccion de la memoria tienes que recordar que se trata de un numero. Entonces printf("%d", cadena);
te da la direccion de la memoria. El estilo para hacerlo en C++ seria:
std::cout << (int)cadena;
nonpromisc: si se puede hacer eso, son literales de cadena.
Zekkk: no van en la pila (si el puntero en si mismo si es una variable local) sino en la sección de datos de solo lectura, por eso si tratas de escribir en ellos se produce una excepcion no controlada.
#include <cstdio>
void main()
{
//char cadena[] = "Hola"; //esto si va en la pila
char *cadena = "Hola";
*cadena = 'B'; //kaboom
printf(cadena);
}
Cintunuando con la explicación de Eterna Idol, decir que una forma de poner en la pila una cadena es mediante el uso de arrays de carácteres:
char str[] = "Una cadena";
Siempre y cuando str sea una variable local. En este caso C crea espacio en la pila y genera el código para copiar 'Una cadena' en ese espacio reservado, mas un caracter nulo, con lo que 'Una cadena' no existe en otro sitio que el archivo fuente de C.
Pero no se puede definir de la manera siguiente
char str[];
str = "Una cadena";
Por el hecho de que str es un puntero estático, no puede apuntar a otro sitio, y ahora "Una cadena" es una constante que se guarda en la zona de memoria de solo lectura. C no genera codigo para copiar el valor sino que interpreta que se quiere que str apunte a la cadena, lo que es ilegal.
Una pregunta
Para evitar esos problemas se usa malloc reservando y posteriormente liberando la memoria, verdad?
Correcto, esta en la sección de datos de solo lectura y el puntero en si en el stack. Y no kondrag, no se reserva memoria usando malloc a menos que realmente lo necesites porque reservar memoria en el "heap" es mucho mas lento que en el stack. Considera que para reservar memoria con malloc() tienes que buscar un bloque de memoria lo suficientemente grande y dividirlo y para empeorar las cosas luego debes liberarlo usando free(). Por otra parte para resevar memoria en el stack solo tienes que cambiar un puntero.
Es decir, solo usa malloc cuando sea absolutamente necesario.
y cuando es necesario? siempre he tenido esa duda
Cuando necesitas acceso a una gran cantidad de memoria. Por ejemplo si quisieras un array bastante grande, o cuando necesitas mantener una variable por mucho tiempo como por ejemplo para una lista enlazada o algo asi.
Cita de: kondrag_X1 en 26 Diciembre 2015, 01:54 AM
y cuando es necesario? siempre he tenido esa duda
Si antes de la compilación no sabes cuánta memoria vas a utilizar para alojar tus variables entonces para no tener que reservar una enorme cantidad de memoria en tiempo de compilación y que al final no vas a terminar de usar entonces reservas memoria en tiempo de ejecución cuando ya conozcas cuánta memoria vas a necesitar.
Imagina que reservas memoria en tiempo de compilación para 200 variables pero al final terminas usando sólo 40 entonces habrás desperdiciado 160, si es posible entonces reservas memoria sólo para esas 40 variables con memoria dinámica. Aunque personalmente sólo uso memoria dinámica cuando sé que la cantidad de memoria que se perderá es grande en caso de no usarla.
ok, gracias a todos yo reservaba memoria siempre que recibía un paquete cuando programa servidores y clientes en C.