[C con Clase] Cadenas estilo C

Sergio Torró storro.zgz en gmail.com
Vie Ago 9 15:18:28 CEST 2013


Gracias por tus aclaraciones, lo he modificado como me has comentado =)
Simplemente una última duda, ¿al usar cin.getline(cad_input,
DEFAULT_CHARS); estoy inicializando el puntero cad_input verdad? ¿En este
caso no es necesario hacer antes cad_input[0] = 0;?

Un saludo.


El 8 de agosto de 2013 17:12, Salvador Pozo <salvador en conclase.net>escribió:

> El pasado 2013-08-08 11:41:36, Sergio Torró escribió:
>
> ST> Muchas gracias Salvador. No sabía que existía un blog de C con Clase!
>
> Hola:
>
> Por cierto, me estoy dando cuenta de que le pasa lo mismo a prácticamente
> todo el mundo. :)
>
> ST> ...mi intención con esto era simplemente
> ST> comprender el manejo de cadenas estilo C (según he leído hay mucho
> código
> ST> heredado y conviene saber del tema).
>
> Siempre es bueno comprender el manejo de cadenas estándar C. Como bien
> dices, hay muchísimo código escrito para ese tipo de cadenas, y muchos
> programadores que aún las usamos, bien sea por costumbre, por cabezonería o
> por desconocimiento de otras opciones.
>
> ST> Por lo que he estado viendo para hacer
> ST> esto de una forma ajustada (sin desperdiciar memoria) sería “necesario”
> ST> utilizar las funciones de memoria dinámica de C (al fin y al cabo estoy
> ST> manejando cadenas estilo C ^^).
>
> No necesariamente. Los operadores new y delete hacen lo mismo que las
> funciones C para manejar memoria. Tal vez eches de menos la función
> realloc, pero es una pérdida menor.
>
> La ventaja de los operadores es que son una abstracción entre el sistema y
> el programador. Añaden otra capa, ya que es posible sobrecargarlos para
> implementar otros tipos de control de memoria. Con las funciones C no se
> puede hacer.
>
> ST> He escrito el siguiente código y lo he
> ST> probado y parece que funciona bien en todos los casos (cadenas largas,
> con
> ST> espacios…):
>
> A mi entender hay algunos errores y cosas que se pueden mejorar en tu
> programa. Comento sobre la marcha.
>
> ST> #include <stdlib.h> //malloc, free, realloc...
> ST> static const size_t DEFAULT_CHARS = 2000;
>
> Un tamaño arbitrario, supongo. Resulta difícil pensar que un usuario
> "normal" introduzca más de 2000 caracteres cuando le pides una cadena, pero
> puede pasar. Es incluso más probable si el usuario no es "normal", sino un
> hacker buscando un buffer para desbordar.
>
> Cierto que el método getline impide que se lean más de DEFAULT_CHARS
> caracteres, de modo que estamos protegidos ante ataques de ese tipo, así
> que de momento, todo bien. :)
>
> ST> int main(void) {
> ST>        const char *concat_str = "este texto se usa para concatenar.";
> ST>        char *cad_input = (char*) malloc(sizeof(char) *
> (DEFAULT_CHARS));
> ST>        cout << "Introduce una cadena: ";
> ST>        cin.getline(cad_input, DEFAULT_CHARS);
> ST>        cad_input = (char*) realloc(cad_input, strlen(cad_input) + 1);
> ST>        cad_input[strlen(cad_input)] = '\0';
>
> Es innecesario añadir el terminador nulo, ya que estaba en la cadena
> original. Más que nada porque si no fuera así, la función strlen no hubiera
> funcionado. Precisamente, lo que hace esa función, es contar caracteres
> hasta que encuentra el primer nulo.
>
> ST>        cout << "Cadena introducida: " << cad_input << endl;
> ST>        char *final_str = (char*)
> ST>              calloc(strlen(cad_input) + strlen(concat_str) + 1,
> sizeof(char
> ST> ));
>
> Me falta un carácter para final_str. Necesitas los suficientes para
> cad_input, concat_str, para el espacio separador y para el nulo terminador.
>
> ST>        strcat(final_str, cad_input);
>
> Nos pasa lo mismo que en el ejemplo anterior. No puedes asegurar que
> final_str tenga una cadena vacía nada más crearla. De hecho, lo más
> frecuente es que no sea así. Hay que inicializar siempre todas las
> variables antes de usarlas, y esto es más importante cuando trabajamos con
> punteros y con memoria dinámica.
>
> Al obtener memoria desde el montón (que es desde donde se obtiene la
> memoria dinámica), no se inicializa el contenido, sólo obtenemos un puntero
> a la memoria reservada.
>
> Podrías usar la función strcpy en lugar de strcat, o iniciar la cadena,
> por ejemplo con final_str[0] = 0;
>
> ST>        strcat(final_str, " ");
> ST>        strcat(final_str, concat_str);
> ST>        //strcat(final_str, "\0");
> ST>        cout << "Cadena concatenada: " << final_str << endl;
> ST>        free(final_str);
> ST>        free(cad_input);
> ST>        return 0;
> ST> }
>
> ST> La única duda que me surge de esto es si es “bueno” hacer un realloc al
> ST> mismo puntero (en este caso cad_input).
>
> No tiene nada de malo. La pregunta sería si es útil hacerlo. Eso dependerá
> de cada caso. En este ejemplo, que evidentemente es muy simple, no aporta
> nada, salvo ahorrar algo de memoria, que de todos modos se libera unos
> segundos después (o unas milésimas de segundo después). :)
>
> ST> PD: Por si interesa, encontré en la documentación de GNU el código de
> las
> ST> funciones estándar y demás implementaciones. Se pueden ver en el
> siguiente
> ST> enlace:
> http://gcc.gnu.org/onlinedocs/gcc-4.8.1/libstdc++/api/files.html
>
> Me guardo el enlace, gracias.
>
> 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/20130809/75ecd406/attachment.html>


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