[C con Clase] Cadenas estilo C

Sergio Torró storro.zgz en gmail.com
Jue Ago 8 13:41:44 CEST 2013


Muchas gracias Salvador. No sabía que existía un blog de C con Clase! Un
artículo interesante, me guardo el blog a la lista de los que frecuento =)

Soy consciente de la existencia de la clase string (y te aseguro que es la
que voy a utilizar siempre ;-P), mi intención con esto era simplemente
comprender el manejo de cadenas estilo C (según he leído hay mucho código
heredado y conviene saber del tema). Por lo que he estado viendo para hacer
esto de una forma ajustada (sin desperdiciar memoria) sería “necesario”
utilizar las funciones de memoria dinámica de C (al fin y al cabo estoy
manejando cadenas estilo C ^^). He escrito el siguiente código y lo he
probado y parece que funciona bien en todos los casos (cadenas largas, con
espacios…):

#include <stdlib.h> //malloc, free, realloc...

static const size_t DEFAULT_CHARS = 2000;


int main(void) {

       const char *concat_str = "este texto se usa para concatenar.";

       char *cad_input = (char*) malloc(sizeof(char) * (DEFAULT_CHARS));



       cout << "Introduce una cadena: ";

       cin.getline(cad_input, DEFAULT_CHARS);



       cad_input = (char*) realloc(cad_input, strlen(cad_input) + 1);

       cad_input[strlen(cad_input)] = '\0';

       cout << "Cadena introducida: " << cad_input << endl;



       char *final_str = (char*)

             calloc(strlen(cad_input) + strlen(concat_str) + 1, sizeof(char
));



       strcat(final_str, cad_input);

       strcat(final_str, " ");

       strcat(final_str, concat_str);

       //strcat(final_str, "\0");



       cout << "Cadena concatenada: " << final_str << endl;



       free(final_str);

       free(cad_input);


       return 0;

}

La única duda que me surge de esto es si es “bueno” hacer un realloc al
mismo puntero (en este caso cad_input). Tampoco hago comprobaciones de
ningún tipo y soy consciente de que se deben hacer (comprobar que cad_input
no es NULL etc…), como he comentado es simplemente un ejercicio para
satisfacer mi curiosidad y manejarme un poco con las cadenas estilo C ^^

Muchas gracias por todo Salvador, has sido de gran ayuda =)

PD: Por si interesa, encontré en la documentación de GNU el código de las
funciones estándar y demás implementaciones. Se pueden ver en el siguiente
enlace: http://gcc.gnu.org/onlinedocs/gcc-4.8.1/libstdc++/api/files.html


El 7 de agosto de 2013 19:23, Salvador Pozo <salvador en conclase.net>escribió:

> Hola:
>
> El pasado 2013-08-07 14:59:38, Sergio Torró escribió:
>
> ST> Muchas gracias por tu respuesta Salvador, te has explicado
> perfectamente :-)
> ST> Deduzco que si quisiera concatenar cadenas que el usuario introduce por
> ST> teclado, tendría que asignar memoria dinámicamente para poder hacerlo,
> ST> ¿verdad?
>
> Efectivamente, necesitarás memoria dinámica, pero eso plantea algunos
> problemas que pasaré a comentarte sobre tu programa.
>
> ST> He escrito el siguiente código y me funciona bien, pero si hay
> ST> algún detalle de los que no se ven a simple vista me encantaría
> saberlo ;-P
> ST> int main(void)
> ST> {
> ST>        char *cad_input = new char;
>
> Esto no es correcto. La expresión "new char" sólo reserva memoria para un
> carácter, y difícilmente podrás almacenar una cadena en un espacio tan
> pequeño.
>
> Para reservar memoria para más de un carácter hay que usar el operador
> new[], de este modo:
>
> char *cad_input = new char[32];
>
> El problema de esto es que tenemos que dimensionar la cadena antes de
> saber qué tamaño va a tener, puesto que aún no hemos leído nada desde el
> teclado, ni tampoco podemos prever qué tipo de cadena va a introducir el
> usuario.
>
> ST>        char cad_concat[] = "-> concatenado con este texto.";
> ST>        char *cad_final = new char;
>
> Lo mismo se aplica a cad_final.
>
> ST>        cout << "Introduce una cadena: ";
> ST>        cin >> cad_input;
> ST>        strcat(cad_final, cad_input);
>
> Aquí hay otro problema. No has inicializado la cadena cad_final, y
> concatenas el contenido inicial, que no conocemos, con el introducido por
> el usuario. El resultado es imprevisible.
>
> ST>        strcat(cad_final, " ");
> ST>        strcat(cad_final, cad_concat);
> ST>        cout << endl << cad_final << endl;
> ST>        delete cad_input;
> ST>        delete cad_final;
>
> Como dices en tu siguiente mensaje, si se usa new[] hay que usar delete[],
> pero en este caso no has usado los corchetes, por lo que, aún estando mal
> el programa, al menos los operadores new y delete son coherentes. :)
>
> ST>        return 0;
> ST> }
>
> ST> Y en este último caso imagino que es mejor utilizar la asignación
> dinámica
> ST> de memoria de C++ y evitar malloc() y realloc(), ¿verdad?
>
> Programando en C++ siempre es preferible usar los operadores que las
> funciones para asignación de memoria. Más que nada porque los operadores se
> pueden sobrecargar o redefinir, para, por ejemplo, diseñar tu propia
> gestión de memoria.
>
> Por cierto, que para evitar los inconvenientes con las cadenas es
> preferible usar la clase para cadenas definida en la cabecera <string>.
>
> Tu programa, usando esa clase, queda así:
> ----8<------
> #include <iostream>
> #include <string>
>
> using namespace std;
>
> int main(void)
> {
>        string cad_input;
>        string cad_concat("-> concatenado con este texto.");
>        string cad_final;
>
>        cout << "Introduce una cadena: ";
>        getline(cin, cad_input);
>
>        cad_final = cad_input + " " + cad_concat;
>
>        cout << endl << cad_final << endl;
>
>        return 0;
> }
> ----8<------
>
> Utilizo la función "getline" en lugar del operador >> para leer cadenas
> porque de ese modo se pueden leer espacios. El operador >> deja de leer al
> encontrar el primer espacio, y deja el resto de la cadena en el buffer de
> entrada, con lo que siguientes lecturas pueden dar un resultado inesperado.
>
> En lugar de la función strcat, puedes usar el operador + para concatenar
> cadenas, o también el operador +=, si lo prefieres.
>
> Recomiendo visitar el artículo del blog sobre validación de dato, ya que
> estamos hablando del tema. :)
>
> http://blogconclase.wordpress.com/2013/06/07/validar-datos-en-c/
>
> 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/20130808/dbdf8176/attachment.html>


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