Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: programator11 en 5 Agosto 2014, 13:17 pm



Título: Espacios en concatenación strcat.
Publicado por: programator11 en 5 Agosto 2014, 13:17 pm
Buenas que tal.

Mi problema es el siguiente, quiero hacer un programa que vaya concatenando las palabras que yo vaya introduciendo por teclado, el problema es que no se como hacer para que se concatenen con un espacio cada palabra (aaa bbb en lugar de aaabbb)

He probado a concatenar un espacio a cada palabra que se introduzc pero no obtengo resultado,aqui mi codigo;

Código:
..........
.........
void funcion()
   {
    char cad[100],pal[18];
    char seg;
    int cont=0;
do
    {
      if (cont==0)
      {
      printf ("\nIntroduzca la primera palabra\n\n");
      scanf ("%s",&pal);
        strcat (cad,pal);
      cont++;
      }
     
      else
      {
      printf ("\nIntroduzca la siguiente palabra de la frase:\n");
      scanf ("%s",&pal);
      strcat (cad,pal);
      }
        printf( "\nSi quieres seguir alargando la frase pulsa S, sino pulsa cualquier otra letra:\n" );
    fflush(stdin);
        scanf( "%c", &c);
   } while ( c == 's' );
    printf ("\n\nLa frase final es \n\n%s",cad);


Gracias de antemano  :)


Título: Re: Espacios en concatenación strcat.
Publicado por: eferion en 5 Agosto 2014, 13:23 pm
Que tal algo del tipo...

Código
  1. char buffer[ 100 ];
  2. strcat( buffer, "palabra1" );
  3. strcat( buffer, " " );
  4. strcat( buffer, "palabra2" );

Por cierto, esta línea, por ejemplo:

Código
  1. scanf ("%s",&pal);

Está mal... pal es de por sí un puntero, si pasas la referencia en vez del puntero vas a escribir donde no debes.

Además:

Código
  1. char cad[ 100 ];
  2. // ...
  3. strcat( cad, pal );

¿Dónde has inicializado "cad"?? strcat concatena a partir del final de cadena, es decir, de que encuentra el carácter nulo... si la cadena no está inicializada vas a tener basura y la función va a concatenar donde le de la gana... y seguro que no coincide con el sitio donde tú quieres que escriba.


Título: Re: Espacios en concatenación strcat.
Publicado por: leosansan en 5 Agosto 2014, 15:56 pm
Buenas que tal.

Mi problema es el siguiente, quiero hacer un programa que vaya concatenando las palabras que yo vaya introduciendo por teclado, el problema es que no se como hacer para que se concatenen con un espacio cada palabra (aaa bbb en lugar de aaabbb)


Además de la solución que te dio eferion te propongo otra alternativa.

Para empezar sacaría el primer scanf del do-while, ya que la primera palabra y la segunda son escaneadas impepinablemente siendo ya optativas las siguientes. Con eso ahorras la variable cont y te evitas el if-else del do-while.

Y para concatenar las palabras usaría la función sprintf con lo que en con sólo una función concateno las palabras:

Código
  1. /***************************************************/
  2.  
  3.  char c , cad[100] = "" , pal[18] ;
  4.  
  5.  printf ( "\nIntroduzca la primera palabra\n\n" ) ;
  6.  scanf ( "%s"  ,pal ) ;
  7.  sprintf ( cad , "%s%s" , cad  , pal ) ;
  8.  
  9.  do {
  10.    printf ( "\nIntroduzca la siguiente palabra de la frase:\n" ) ;
  11.    scanf ( "%s" , pal) ;
  12.    sprintf ( cad , "%s%c%s" , cad , ' ' , pal ) ;
  13.    printf( "\nSi quieres seguir alargando la frase pulsa S, sino pulsa cualquier otra letra:\n" ) ;
  14.    scanf( " %c", &c) ; /* Observa el espacio en blanco antesde %c para limpiar el '\n' del scanf previo */
  15.  } while ( c == 's' ) ;
  16.  
  17.   printf ( "\n\nLa frase final es \n\n%s" , cad ) ;
  18.  
  19. /********************************************************/

Y respecto al uso de scanf y  fflush (stdin) te aconsejaría leer lo que no hay que hacer en C/C++. Nivel basico (http://foro.elhacker.net/programacion_cc/lo_que_no_hay_que_hacer_en_cc_nivel_basico-t277729.0.html).

En cualquier caso si veo necesario el uso de una condición que controle el tamaño de la cadena "cad" tal que si se supere su tamaño aborte el ciclo y no permita añadir más palabras pues en caso contrario se iría más allá de la dimensión de la mencionada cadena cad.También es necesario controlar que la variable "palabra" introducida sucesivamente no supere en cada caso su tamaño y tienes ejemplo de eso en el enlace anterior. Eso ya te lo dejo a ti aunque es sencillito.  ;)

¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/simba2.gif)


Título: Re: Espacios en concatenación strcat.
Publicado por: Blaster en 5 Agosto 2014, 16:55 pm
O podrías implementar tu propia versión de strcat así para ajustarlo a tus necesidades y evitar tantas llamadas de la versión estándar :

Código
  1. char *my_strcat(char *s, char esp, char *cad)
  2. {
  3.    char *save = s;
  4.  
  5.    for (; *s; ++s);
  6. *s = esp;
  7.    while ((*++s = *cad++) != '\0');
  8.  
  9.    return(save);
  10. }
  11.  
  12. int main(void)
  13. {
  14.    char s[80] = "hola";
  15.    char p[80] = "mundo";
  16.  
  17.    my_strcat(s, ' ', p);
  18.  
  19.    printf("%s", s);
  20.  
  21.    return 0;
  22. }
  23.  

Saludos


Título: Re: Espacios en concatenación strcat.
Publicado por: eferion en 5 Agosto 2014, 17:12 pm
O podrías implementar tu propia versión de strcat así para ajustarlo a tus necesidades y evitar tantas llamadas de la versión estándar :

Código
  1. char *my_strcat(char *s, char esp, char *cad)
  2. {
  3.    char *save = s;
  4.  
  5.    for (; *s; ++s);
  6. *s = esp;
  7.    while ((*++s = *cad++) != '\0');
  8.  
  9.    return(save);
  10. }
  11.  
  12. int main(void)
  13. {
  14.    char s[7] = "hola";
  15.    char p[] = "mundo";
  16.  
  17.    my_strcat(s, ' ', p);
  18.  
  19.    printf("%s", s);
  20.  
  21.    return 0;
  22. }
  23.  

Saludos

Eres consciente que tu ejemplo escribe fuera del buffer, no?? ... o perdón, hablando con propiedad... provoca buffer overflow.

A ver, ya puestos, no tiene mucho sentido que el "remedio" consista en crear una versión de strcat que permita concatenar dos cadenas por vez en vez de una...

Si pretendemos ahorrar llamadas al menos tenemos que intentar hacerlo con un poco de sentido... no viene a cuento reinventar la rueda... ten por seguro que la implementación de la librería estándar es, en el peor de los casos, igual de eficiente que la tuya... lo lógico es que esa versión tienda a ser más eficiente que la tuya. Y aunque esta no fuese razón suficiente, piensa que la librería estándar va a tener muchos menos errores de código que tu versión... además que te evitas tener que mantener ese código.

Código
  1. char* my_strcat( char*s, const char*cad )
  2. {
  3.  if ( *s != 0 )
  4.    strcat( s, " " );
  5.  
  6.  strcat( s, cad );
  7.  
  8.  return s;
  9. }

Pd.: tampoco he entendido muy bien la utilidad de la variable "save";



Título: Re: Espacios en concatenación strcat.
Publicado por: Blaster en 5 Agosto 2014, 17:25 pm
Eres consciente que tu ejemplo escribe fuera del buffer, no?? ... o perdón, hablando con propiedad... provoca buffer overflow.

Uff es que lo estaba probando y olvide ponerle el tamaño actual gracias por la observación

Saludos


Título: Re: Espacios en concatenación strcat.
Publicado por: eferion en 5 Agosto 2014, 17:29 pm
Uff es que lo estaba probado y olvide ponerle el tamaño actual gracias por la observación

Saludos

Son cosas que pasan... es que lo he visto nada más ver el código... que, dicho sea de paso, no es culpa de la función sino de cómo ha sido declarada la variable.


Título: Re: Espacios en concatenación strcat.
Publicado por: Swain en 5 Agosto 2014, 17:51 pm
Si no sabes el largo que va a tomar la frase tienes que usar punteros
pero para cada palabra puedes asignarle un espacio TOPE


Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. char *funcion(){
  6. char *frase;
  7. bool cont = true;  // CONDICIONAL PARA CONTINUAR O SALIR
  8. char aux[50]; /// MAXIMO 50 CARACTERES POR PALABRA
  9. frase = (char *)malloc(sizeof(aux));// INICIO CON AL MENOS CON 1 PALABRA
  10. memset(frase,'\0',strlen(frase));
  11. while(cont){
  12. memset(aux,'\0',sizeof(aux)); //LIMPIO AUXILIAR ANTES DE COMENZAR
  13. printf("escribe palabra: ");
  14. scanf("%s",&aux);
  15. sprintf(frase,"%s %s",frase,aux); //CONCATENO FRASE ARMADA + PALABRA
  16. printf("Dese continuar?(y/n)");
  17. memset(aux,'\0',sizeof(aux));
  18. scanf("%s",&aux);
  19. if(aux[0] == 'n' || aux[0] == 'N') //SI EMPIEZA CON N o n SALGO
  20. cont = false;
  21.       frase = (char *)realloc(frase,sizeof(aux)+strlen(frase)); //PIDO MAS ESPACIO
  22. }
  23.  
  24. return frase; // DEVUELVO LA FRASE TERMINADA
  25. }
  26.  
  27.  
  28. int main(){
  29.  
  30. printf("la frase es: %s\r\n",funcion());
  31. return 0;
  32. }
  33.  


Título: Re: Espacios en concatenación strcat.
Publicado por: eferion en 5 Agosto 2014, 17:58 pm
Si no sabes el largo que va a tomar la frase tienes que usar punteros

... y si sabes la longitud ... también.

Las cadenas de caracteres van siempre con punteros.

PD.: lo siento hoy estoy quisquilloso... te falta un free so pena de tener lagunas de memoria.

PD2.: hay que tener cuidado con las reservas de memoria ( malloc, calloc, realloc ). Estas funciones están pensadas para hacer reservas grandes de memoria... con reservas pequeñas son bastante ineficientes... además, realloc tiene el problema añadido de mover información de una posición de memoria a otra... luego andar haciendo realloc cada dos por tres no parece una opción muy atractiva... casi es mejor hacer realloc de forma exponencial... reservando bloques cada vez más grandes de memoria precisamente para realizar la menor cantidad de llamadas posibles. Escatimar recursos a este nivel solo es útil en sistemas empotrados o con recursos escasos, en el resto de casos no merece la pena.


Título: Re: Espacios en concatenación strcat.
Publicado por: Blaster en 5 Agosto 2014, 18:45 pm
ten por seguro que la implementación de la librería estándar es, en el peor de los casos, igual de eficiente que la tuya... lo lógico es que esa versión tienda a ser más eficiente que la tuya. Y aunque esta no fuese razón suficiente, piensa que la librería estándar va a tener muchos menos errores de código que tu versión... además que te evitas tener que mantener ese código.

Dudo que la versión estándar sea tan diferente, es mas apostaría que es igual a:

Código
  1. char *strcat(char *s, const char *cad)
  2. {
  3.    char * save = s;
  4.    for (; *s; ++s);
  5.    while ((*s++ = *cad++) != '\0');
  6.  
  7.    return (save);
  8. }

Y la verdad no sé que la hace tan "eficiente" ya que ni siquiera realiza la validación
pertinente para asegurar que la cadena destino sea lo suficientemente grande para
luego concatenarle la cadena indicada.

Saludos


Título: Re: Espacios en concatenación strcat.
Publicado por: leosansan en 5 Agosto 2014, 20:25 pm
Si no sabes el largo que va a tomar la frase tienes que usar punteros
pero para cada palabra puedes asignarle un espacio TOPE

Me ha gustado el uso del puntero con asignación dinámica de memoria, eso sí con lo que tan acertadamente comenta eferion respecto a dicha asignación así como el uso del bool.  ;-)

Sólo unos pequeñitos detalles:

* creo que falta la librería stdbool.h
* ¿No te sobra el "&" en los scanf al tratarse de arrays?.
* Tal como lo tienes, introduce un espacio en blanco al comienzo de la frase, cosa que no procede.
* ¿Es tan necesario el uso de memset?. Para inicializar "frase " podríamos usar calloc, en lugar de malloc, y respecto a inicializar a la variable "aux", ¿es tan necesario?. Dudas, dudas ..... :rolleyes:
* Podemos ahorrarnos uno de los scanf haciendo la pregunta al entrar la frase.

Son sólo detallitos sin mayor importancia pero creo que eferion me ha contagiado el estado "quisquilloso" hoy.  :laugh:

Pero insisto, me ha gustado la aportación, tanto que con tu permiso la modifico para tener en cuenta los pequeñitos detalles que mencioné:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdbool.h>
  5.  
  6. char *funcion ( char *frase ) {
  7.  bool cont = true ;
  8.  char aux [ 50 ] ;
  9.  frase = calloc ( sizeof  aux , sizeof ( char ) ) ;
  10.  printf("\nEscribe una palabra ( n para salir ): ") ;
  11.  scanf ( "%s" , aux ) ;
  12.  strcpy( frase , aux ) ;
  13.  while ( cont ) {
  14.    printf("\nEscribe una palabra ( n para salir ): ") ;
  15.    scanf ( "%s" , aux ) ;
  16.    ( strlen ( aux ) == 1 && ( aux[0] == 'n' || aux[0] == 'N') ) ? cont = false : sprintf ( frase , "%s %s" , frase , aux ) ;
  17.    frase = realloc ( frase , sizeof ( aux ) + strlen ( frase ) ) ;
  18.  }
  19.  return frase ;
  20. }
  21.  
  22. int main( ) {
  23.  char *frase ;
  24.  printf( "\n\nLa frase es:\n\n%s" , funcion ( frase ) ) ;
  25.  free ( frase ) ;
  26.  return EXIT_SUCCESS ;
  27. }

¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/aaaaa.gif)


Título: Re: Espacios en concatenación strcat.
Publicado por: eferion en 6 Agosto 2014, 08:35 am
Dudo que la versión estándar sea tan diferente, es mas apostaría que es igual a:

Código
  1. char *strcat(char *s, const char *cad)
  2. {
  3.    char * save = s;
  4.    for (; *s; ++s);
  5.    while ((*s++ = *cad++) != '\0');
  6.  
  7.    return (save);
  8. }

Y la verdad no sé que la hace tan "eficiente" ya que ni siquiera realiza la validación
pertinente para asegurar que la cadena destino sea lo suficientemente grande para
luego concatenarle la cadena indicada.

Saludos

No estoy hablando de una función concreta... hablo en general.

Porque claro, ya puestos, una vez has creado tu versión de strcat (pensando en que debe funcionar igual que la función estándar)... ¿por qué no hacer una implementación propia de strlen, strcpy, strtok, memcpy, memset... ¿eres capaz de garantizar que tus versiones van a ser igual de óptimas que las versiones estándar? estoy convencido de que no. Si miras el código fuente de algunas de estas funciones verás que están plagadas de compilaciones condicionales... precisamente para optimizar y para sortear eventualidades (no es lo mismo una arquitectura big endian que una little endian, por ejemplo)... y está claro que tú no vas a tener en cuenta estas cosas. Al final, por este camino, tu código acabaría siendo poco eficiente y no portable.... y ese no es el camino.


Título: Re: Espacios en concatenación strcat.
Publicado por: leosansan en 7 Agosto 2014, 00:07 am
No estoy hablando de una función concreta... hablo en general.

 Al final, por este camino, tu código acabaría siendo poco eficiente y no portable.... y ese no es el camino.

Pues usemos dichas funciones. Como ejemplo:

Código
  1. char *my_strcat( char *s , char esp , char *cad ) {
  2.  sprintf ( s , "%s %s" , s , cad)  ;
  3.  return( s ) ;
  4. }


¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/simba2.gif)



Título: Re: Espacios en concatenación strcat.
Publicado por: rir3760 en 7 Agosto 2014, 20:05 pm
para concatenar las palabras usaría la función sprintf con lo que en con sólo una función concateno las palabras:

[...]

Código
  1. sprintf(cad, "%s%c%s", cad, ' ', pal);
Un problema con esa llamada a sprintf es indicar que la cadena debe imprimirse sobre si misma y en caso de utilizar el par strcpy/strcat se tiene el fastidio (con la segunda) de buscar el final de la primera cadena.

En su lugar se puede aprovechar el valor de retorno de sprintf, este es el numero de caracteres generados en base a la cadena de formato sin incluir el '\0'. Un ejemplo basado en el tuyo sin validaciones ni uso de memoria dinámica:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5.  
  6. #define MAX_PAL  50
  7.  
  8. char *funcion(char *frase);
  9.  
  10. int main(void)
  11. {
  12.   char frase[MAX_PAL * 20];
  13.  
  14.   printf("La frase es: \"%s\"\n", funcion(frase));
  15.  
  16.   return EXIT_SUCCESS;
  17. }
  18.  
  19. char *funcion(char *frase)
  20. {
  21.   char pal[MAX_PAL];
  22.   int nc;
  23.  
  24.   puts("Escribe una palabra ( n para salir ):");
  25.   scanf("%s", pal);
  26.   nc = sprintf(frase, "%s", pal);
  27.  
  28.   while (1){
  29.      puts("Escribe una palabra (n para salir):");
  30.      scanf("%s", pal);
  31.  
  32.      if (tolower(*pal) == 'n' && pal[1] == '\0')
  33.         break;
  34.  
  35.      nc += sprintf(frase + nc, " %s", pal);
  36.   }
  37.  
  38.   return frase;
  39. }

Un saludo