[C con Clase] Cadenas estilo C

Sergio Torró storro.zgz en gmail.com
Mie Ago 7 17:27:46 CEST 2013


Acabo de darme cuenta que debería ser así:

delete [] cad_input;

delete [] cad_final;

De todas formas me estoy oliendo algo a podrido en mi código... es
obligatorio especificar el tamaño del array cierto? (char *cad_final = new
char[500]; por ejemplo). Algo estoy haciendo mal :-(


El 7 de agosto de 2013 16:59, Sergio Torró <storro.zgz en gmail.com> escribió:

>
> Muchas gracias por tu respuesta Salvador, te has explicado perfectamente
> :-)
>
> Deduzco que si quisiera concatenar cadenas que el usuario introduce por
> teclado, tendría que asignar memoria dinámicamente para poder hacerlo,
> ¿verdad? He escrito el siguiente código y me funciona bien, pero si hay
> algún detalle de los que no se ven a simple vista me encantaría saberlo ;-P
>
> int main(void)
>
> {
>
>        char *cad_input = new char;
>
>        char cad_concat[] = "-> concatenado con este texto.";
>
>        char *cad_final = new char;
>
>
>
>        cout << "Introduce una cadena: ";
>
>        cin >> cad_input;
>
>
>
>        strcat(cad_final, cad_input);
>
>        strcat(cad_final, " ");
>
>        strcat(cad_final, cad_concat);
>
>
>
>        cout << endl << cad_final << endl;
>
>
>
>        delete cad_input;
>
>        delete cad_final;
>
>
>
>        return 0;
>
> }
>
> Y en este último caso imagino que es mejor utilizar la asignación dinámica
> de memoria de C++ y evitar malloc() y realloc(), ¿verdad?
>
> Un saludo y gracias por tu tiempo.
>
>
> El 6 de agosto de 2013 20:47, Salvador Pozo <salvador en conclase.net>escribió:
>
> El pasado 2013-08-06 16:48:20, Sergio Torró escribió:
>>
>> ST> Muy buenas a todos. Me gustaría comentar una duda (seguramente muy
>> tonta)
>> ST> sobre el manejo de cadenas estilo C. Tengo el siguiente código que
>> funciona
>> ST> perfectamente:
>> ST> #include <iostream>
>> ST> using std::cout;
>> ST> using std::endl;
>> ST> #include <cstring>
>> ST> using std::strcat;
>> ST> int main(void) {
>> ST>        char cadena1[] = "Hola";
>> ST>        char cadena2[] = "Perico";
>> ST>        strcat(cadena1, " ");
>> ST>        strcat(cadena1, cadena2);
>> ST>        cout << cadena1 << endl;
>> ST>        return 0;
>> ST> }
>> ST> Echándole un ojo a la declaración de strcat veo que sus parámetros son
>> ST> punteros (char*, const char*) y se me ocurrió probar a declarar mis
>> dos
>> ST> cadenas de caracteres como tales: char *cadena1 = "Hola"; Si hago ese
>> ST> cambio, no funciona.
>> ST> Creo entender la diferencia entre un array de chars y un puntero: si
>> no me
>> ST> equivoco el array reserva espacio para cada char que contiene la
>> cadena. Si
>> ST> lo declaro como un puntero, se reserva espacio para almacenar
>> simplemente
>> ST> un puntero que puede apuntar a cualquier cadena de chars. Mi duda es:
>> si
>> ST> esa función está esperando un puntero a una cadena, ¿no debería
>> funcionar
>> ST> si le paso eso mismo? ¿No se supone que el nombre del array (en este
>> caso
>> ST> cadena1) es un puntero al primer elemento de la cadena?
>>
>> A ver si puedo explicar con claridad lo que está pasando en este ejemplo.
>>
>> Cuando declaras las cadenas como arrays, el compilador, como bien dices,
>> reserva espacio suficiente para contener la cadena declarada.
>>
>> El problema no es tanto cuanta memoria reserva el compilador como dónde
>> la reserva.
>>
>> Cuando se trata de un array, la memoria para las cadenas se obtiene de la
>> pila, y los literales de inicialización, en este caso "Hola" y "Perico" se
>> copian desde su origen inicial a las direcciones asignadas a los arrays.
>>
>> En este caso, el programa funciona porque se dan algunas circunstancias
>> "afortunadas".
>>
>> Una de ellas es que las cadenas son cortas, pero al copiar una cadena a
>> continuación de la otra, estamos corrompiendo la memoria que no pertenece
>> al array, y por lo tanto, corrompemos la pila. Como son cadenas cortas,
>> tenemos al suerte de no corromper dados sensibles, pero si fueran cadenas
>> más largas esto no sería así.
>>
>> La otra es el orden en que hemos declarado las variables.
>>
>> Prueba esto:
>> ----8<------
>> #include <iostream>
>> using std::cout;
>> using std::endl;
>>
>> #include <cstring>
>> using std::strcat;
>>
>> int main(void) {
>>        char cadena1[] = "Hola";
>>        char cadena2[] = "Perico";
>>        cadena2[6] = ' ';
>>        cout << cadena2 << endl;
>>        return 0;
>> }
>> ----8<------
>>
>> La salida, en este caso, es "Perico Hola". Esto es porque al almacenarse
>> en la pila, las variables se crean de arriba a abajo, es decir, cada
>> variable local tiene direcciones de memoria menores que las anteriores. El
>> resultado es que primero se almacena en la pila "Hola", y a continuación,
>> en posiciones correlativas, pero menores, "Perico", con el carácter nulo
>> terminador.
>>
>> En este programa hemos sustituido el terminador de "Perico" por un
>> espacio, y por eso se concatenan (aparentemente) las dos cadenas.
>>
>> Si declaras las variables en otro orden, probablemente destruyas una al
>> intentar concatenarlas.
>>
>> Cuando sustituyes las cadenas por punteros, los punteros se siguen
>> almacenando en la pila, pero en lugar de copiar las cadenas al inicial el
>> programa, sólo copia las direcciones. Las cadenas se almacenan junto con el
>> programa ejecutable.
>>
>> La mayor diferencia en este caso es que el sistema operativo protege las
>> direcciones de memoria donde se almacena el programa para que no puedan ser
>> modificadas, o al menos para detectar cuando han sido modificadas. Esto es
>> lo que provoca la excepción "segmentation fault".
>>
>> Una pista en este caso son los mensajes de aviso del compilador:
>>
>> \main.cpp|9|warning: deprecated conversion from string constant to
>> 'char*' [-Wwrite-strings]|
>>
>> Ya te está avisando que estás intentando convertir una cadena constante
>> en un puntero a char, y que eso está desaconsejado.
>>
>> Constante significa que no puede modificarse su valor, y eso es
>> precisamente lo que intentas hacer con strcat.
>>
>> En cualquiera de los dos casos estamos diseñando mal el programa, ya que
>> intentamos copiar cadenas usando objetos (punteros o arrays), que no tienen
>> la capacidad suficiente para contenerlas.
>>
>> ST> He pensado que
>> ST> tiene que ver con la implementación de la función strcat la cual me
>> ST> gustaría ver, ¿hay alguna forma donde pueda ver la implementación de
>> dichas
>> ST> funciones? Vengo de Java y estoy muy acostumbrado en Eclipse a hacer
>> un
>> ST> “Control + clic” en el elemento que quiero ver su implementación ^^
>> ST> Imagino que para el compilador de GNU no será un problema ver la
>> ST> implementación (¿simplemente descargar las fuentes verdad?). ¿Es
>> posible
>> ST> hacerlo también en Visual Studio? Uso Code::Blocks y Visual Studio a
>> partes
>> ST> iguales.
>>
>>
>> No he encontrado los fuentes para strcat, tampoco he buscado mucho, la
>> verdad. :) Sobre todo porque la implementación de esa función no tiene
>> importancia en este caso.
>>
>> Una posible implementación podría ser:
>>
>> ----8<------
>> char *strcat(char *dst, const char *src)
>> {
>>     char *ret = dst;
>>
>>     for (; *dst; ++dst);
>>     while ((*dst++ = *src++) != '\0');
>>     return ret;
>> }
>> ----8<------
>>
>> Sin embargo, estas funciones ni siquiera tienen por qué estar escritas en
>> C, ya que generalmente se trata de librerías de uso frecuente, suelen estar
>> muy optimizadas, y frecuentemente se escriben en ensamblador.
>>
>> Hasta pronto.
>>
>> --
>> Salvador Pozo (Administrador)
>> mailto:salvador en conclase.net
>> Blog con Clase: http://blogconclase.wordpress.com
>> Con Clase: http://conclase.net
>> _______________________________________________
>> Lista de correo Cconclase Cconclase en listas.conclase.net
>> http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
>> Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
>
>
>
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20130807/30708d4c/attachment.html>


Más información sobre la lista de distribución Cconclase