elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Rompecabezas de Bitcoin, Medio millón USD en premios


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Copiando cadenas - comportamientos extraños
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Copiando cadenas - comportamientos extraños  (Leído 3,144 veces)
ryan parker

Desconectado Desconectado

Mensajes: 81



Ver Perfil
Copiando cadenas - comportamientos extraños
« en: 15 Abril 2014, 07:32 am »

Estaba revisando uno viejo libro que hace mucho tiempo imprimi, y me llamo la atencion, asi comienza parte del codigo:

Código
  1. char texto1[40], texto2[40]...
  2. ...
  3. gets(texto1)
  4. ...
  5. strncpy(texto3, texto2, 4);
  6. printf("Sus 4 primeras letras son %s\n", texto3);

Asi que como observer arreglos, quice hacerlo con punteros y ver su funcionamiento.

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. int main(void)
  6. {
  7.    char* saludo;
  8.    int n;
  9.  
  10.    printf("Texto: ");
  11.    gets(saludo);
  12.  
  13.    printf("Cuantas letras desea ver: ");
  14.    scanf("%d", &n);
  15.  
  16.    char* copySaludo = malloc((strlen(saludo) + 1) * sizeof(char));
  17.    strncpy(copySaludo, saludo, n);
  18.  
  19.    printf("Resultado con los %d primeras letras: %s\n", n, copySaludo);
  20.  
  21.    return 0;
  22. }

Lo curioso es que a veces tengo resultados muy fuera de si:
Citar
Texto: hello, world!
Cuantas letras desea ver: 6
Resultado con los 6 primeras letras: hello,>

Citar
Texto: hello, world!
Cuantas letras desea ver: 7
Resultado con los 7 primeras letras: hello,

Citar
Texto: hello, world!
Cuantas letras desea ver: 5
Resultado con los 5 primeras letras: hello♣>

Y a veces provoca un crash!

Es algo extraño, y confuso... creo que jugar con punteros es para super-heroes!
Saludos.


En línea

Your kung-fu is not strong!
rir3760


Desconectado Desconectado

Mensajes: 1.639


Ver Perfil
Re: Copiando cadenas - comportamientos extraños
« Respuesta #1 en: 15 Abril 2014, 08:04 am »

Los errores principales son dos:

* Utilizas el puntero "saludo" sin inicializar:
Código
  1. char* saludo;
  2.  
  3. /* ... */
  4.  
  5. gets(saludo);
Debes reservar un bloque de memoria, almacenar la dirección de este en esa variable y solo entonces la utilizas (sin validaciones):
Código
  1. char *saludo;
  2.  
  3. /* ... */
  4.  
  5. saludo = malloc(100);
  6. puts("Texto:");
  7. gets(saludo);

* La función strncpy copia como máximo el numero de caracteres indicado pero, si copia el máximo, no agrega el '\0'. Bien verificas el numero de caracteres de antemano (lo cual pone fuera de lugar el uso de esa función) o agregas el '\0' de forma manual. Por lo anterior es mejor utilizar sprintf, de esta forma:
Código
  1. char *copySaludo = malloc(n + 1);
  2. sprintf(copySaludo, "%.*s", n, saludo);
  3. printf("Las %d primeras letras: \"%s\"\n", n, copySaludo);

----

Ademas de eso hay otras cosas que, sin ser errores, deberías cambiar en el programa como eliminar el uso de "sizeof(char)" (este siempre es igual a uno) y cambiar el uso de gets por fgets. Mas información en la pagina |Lo que no hay que hacer en C/C++. Nivel basico|.

Un saludo


En línea

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language
amchacon


Desconectado Desconectado

Mensajes: 1.211



Ver Perfil
Re: Copiando cadenas - comportamientos extraños
« Respuesta #2 en: 15 Abril 2014, 22:10 pm »

* Utilizas el puntero "saludo" sin inicializar:
Código
  1. char* saludo;
  2.  
  3. /* ... */
  4.  
  5. gets(saludo);
Debes reservar un bloque de memoria, almacenar la dirección de este en esa variable y solo entonces la utilizas (sin validaciones):
Código
  1. char *saludo;
  2.  
  3. /* ... */
  4.  
  5. saludo = malloc(100);
  6. puts("Texto:");
  7. gets(saludo);
ANEXO: También puedes declarar un array de char[100] y listo.
En línea

Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar
ryan parker

Desconectado Desconectado

Mensajes: 81



Ver Perfil
Re: Copiando cadenas - comportamientos extraños
« Respuesta #3 en: 16 Abril 2014, 06:14 am »

Gracias por sus respuestas.

Reconozco mi error grave de declarar un puntero sin inicializar, tenia un concepcion de querer hacerlo dinamico para la lectura de cadenas, veo que eso es altamente complejo.

Por que si declaro
Código
  1. char* saludo = malloc(100);
Es en si esquivalente ah:
Código
  1. char saludo[100]

Aunque desconozco si el declarar char, vayan al heap; caso que sucede con el malloc.

Ahora si quisiera usar fgets, tendria que saber de antemano cuanto caracteres voy a ingresar (lo digo por el segundo argumento "int length"), cosa que no se acomoda a mis intenciones.

Aceptar tambien que usar gets, era de muy pero muy mala practica acabo de observar que en los man-pages de la terminal gnu/linux, lo clasifican de obsoleto en el standard 2011.

Con respecto a esta linea de codigo:
Código
  1. malloc((strlen(saludo) + 1) * sizeof(char))
tengo un habito de calcular los arreglo y de ahi multiplicarlos por su tipo de dato, si este cambia a int, float y lo tengo ya ganado.
Pero estoy para aprender nuevos y buenos habitos, no se si estoy haciendo bien con el anterior malloc.

lo del strncpy, podria agregar una linea:
Código
  1. copysaludo[n] = '\0';

Pero muy elegante lo del sprintf, una linea y cumple el proposito.

Aprendiendo C, a paso de tortuga, jeje..

Saludos!
En línea

Your kung-fu is not strong!
amchacon


Desconectado Desconectado

Mensajes: 1.211



Ver Perfil
Re: Copiando cadenas - comportamientos extraños
« Respuesta #4 en: 16 Abril 2014, 12:11 pm »

Citar
Ahora si quisiera usar fgets, tendria que saber de antemano cuanto caracteres voy a ingresar (lo digo por el segundo argumento "int length"), cosa que no se acomoda a mis intenciones.
Te confundes, el segundo argumento es el número de caracteres MAXIMO. Puedes meter menos perfectamente.

Lo cual tiene sentido para evitar meter más caracteres de los que caben en el array.
En línea

Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar
ryan parker

Desconectado Desconectado

Mensajes: 81



Ver Perfil
Re: Copiando cadenas - comportamientos extraños
« Respuesta #5 en: 16 Abril 2014, 18:32 pm »

Claro si defino una constante de un tamaño maximo y no sobrepase ese tamaño funcionara correctamente, de lo contrario esto resultaria en un crash, digamos asi:

Código
  1. char* saludo = malloc(10);
  2. /*...*/
  3. printf("Texto: ");
  4. fgets(saludo, 10, stdin);
  5. /*...*/

Al hacer pruebas obtenemos crash, si hago lo siguiente:
texto: hello, hi!

el texto "hello, hi!", tiene 10 en longitud faltando un '\0' para terminar la cadena, me provoca el crash. Es por eso que citaba "es bastante complejo leer cadenas" si se quiere hacer dinamicamente. y funciona correctamente si leo menores a 10 de longitud.

Saludos!
En línea

Your kung-fu is not strong!
Eternal Idol
Kernel coder
Moderador
***
Desconectado Desconectado

Mensajes: 5.969


Israel nunca torturó niños, ni lo volverá a hacer.


Ver Perfil WWW
Re: Copiando cadenas - comportamientos extraños
« Respuesta #6 en: 16 Abril 2014, 20:18 pm »

Eso es por pasarle incorrectamente el segundo parametro:
num
Maximum number of characters to be copied into str (including the terminating null-character).

EDITO:

aunque en este caso el tamaño es correcto asi que si te da algun error es por otra razon. La cadena es truncada correctamente y su contenido es "hello, hi\0".
« Última modificación: 16 Abril 2014, 20:42 pm por Eternal Idol » En línea

La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón
ryan parker

Desconectado Desconectado

Mensajes: 81



Ver Perfil
Re: Copiando cadenas - comportamientos extraños
« Respuesta #7 en: 23 Abril 2014, 05:54 am »

Exacto, cuando la cadena es: 'hello, hi'

Este tendra 9 en longitud, y fgets se encargara de ponerle el '\0' al final, para cumplir con el maximo tamaño permitido, evitando caer en crash y si no me equivoco esto es lo que llaman buffer overflows.

Decia 'complejo' para poder obtener una cadena al menos de una forma segura, y de forma dinamica. Esto es debido por que estuve revisando una funcion que forma parte de un codigo que oculta todo estos detalles, expongo:

Código
  1. string GetString(void)
  2. {
  3.    // growable buffer for chars
  4.    string buffer = NULL;
  5.  
  6.    // capacity of buffer
  7.    unsigned int capacity = 0;
  8.  
  9.    // number of chars actually in buffer
  10.    unsigned int n = 0;
  11.  
  12.    // character read or EOF
  13.    int c;
  14.  
  15.    // iteratively get chars from standard input
  16.    while ((c = fgetc(stdin)) != '\n' && c != EOF)
  17.    {
  18.        // grow buffer if necessary
  19.        if (n + 1 > capacity)
  20.        {
  21.            // determine new capacity: start at 32 then double
  22.            if (capacity == 0)
  23.            {
  24.                capacity = 32;
  25.            }
  26.            else if (capacity <= (UINT_MAX / 2))
  27.            {
  28.                capacity *= 2;
  29.            }
  30.            else
  31.            {
  32.                free(buffer);
  33.                return NULL;
  34.            }
  35.  
  36.            // extend buffer's capacity
  37.            string temp = realloc(buffer, capacity * sizeof(char));
  38.            if (temp == NULL)
  39.            {
  40.                free(buffer);
  41.                return NULL;
  42.            }
  43.            buffer = temp;
  44.        }
  45.  
  46.        // append current character to buffer
  47.        buffer[n++] = c;
  48.    }
  49.  
  50.    // return NULL if user provided no input
  51.    if (n == 0 && c == EOF)
  52.    {
  53.        return NULL;
  54.    }
  55.  
  56.    // minimize buffer
  57.    string minimal = malloc((n + 1) * sizeof(char));
  58.    strncpy(minimal, buffer, n);
  59.    free(buffer);
  60.  
  61.    // terminate string
  62.    minimal[n] = '\0';
  63.  
  64.    // return string
  65.    return minimal;
  66. }

Anotar que el tipo de dato 'string', esta previamente definido en una libreria aparte como:
Código
  1. typedef char* string;

Aunque en este ultimo codigo no entiendo la linea:
Código
  1. string temp = realloc(buffer, capacity * sizeof(char));
Por que si buffer comenzo con NULL, al llegar a esta linea como que asignara NULL para temp, y esto a mi entender como que terminaria el programa  :-X

Saludos!
En línea

Your kung-fu is not strong!
rir3760


Desconectado Desconectado

Mensajes: 1.639


Ver Perfil
Re: Copiando cadenas - comportamientos extraños
« Respuesta #8 en: 23 Abril 2014, 16:53 pm »

Aunque en este ultimo codigo no entiendo la linea:
Código
  1. string temp = realloc(buffer, capacity * sizeof(char));
Por que si buffer comenzo con NULL, al llegar a esta linea como que asignara NULL para temp, y esto a mi entender como que terminaria el programa
No hay problema con esa linea ya una llamada a realloc con su primer argumento igual a NULL tiene el mismo efecto que llamar a malloc: se reserva un bloque de memoria con el tamaño indicado y cuyo contenido es no definido.

Por ejemplo:
Código
  1. p = realloc(NULL, 100); /* mismo efecto que "p = malloc(100);" */

Un saludo
En línea

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Copiando CD's
Software
Dark Shadow 2 2,313 Último mensaje 16 Mayo 2005, 11:35 am
por Dark Shadow
Error copiando cadenas con strcpy (coredump)
Programación C/C++
rixi15 3 2,795 Último mensaje 4 Enero 2012, 15:24 pm
por Eternal Idol
Duda sobre comportamientos variables en la inteligencia artificial
Foro Libre
crazykenny 2 3,442 Último mensaje 26 Octubre 2012, 10:55 am
por crazykenny
Gmail se llena de mensajes de error y comportamientos extraños
Noticias
wolfbcn 0 1,326 Último mensaje 30 Marzo 2015, 21:53 pm
por wolfbcn
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines