Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Bob1098 en 15 Septiembre 2014, 16:51 pm



Título: Calcular longitud de cadena C++ (punteros)
Publicado por: Bob1098 en 15 Septiembre 2014, 16:51 pm
Hola a todos, estoy intentando resolver un ejercicio de c++ que dice lo siguiente:

"Escribir un programa con una función que calcule la longitud de una cadena de caracteres. El nombre de la función será LongitudCadena, debe devolver un int, y como parámetro de entrada debe tener un puntero a char.
 En esta función no se pueden usar enteros para recorrer el array, usar sólo punteros y aplicar aritmética de punteros.
 En main probar con distintos tipos de cadenas: arrays y punteros."

Supongo que no vale esto de recorrer el array con un entero y luego devolver dicho entero, por tanto he probado con esto:

Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. int LongitudCadena(char*);
  6.  
  7. int main() {
  8. char cadena[10];
  9. char *pCadena = 0;
  10.  
  11. cout << "Introduce una cadena como array: ";
  12. cin >> cadena;
  13. cout << "Su tamano es: " << LongitudCadena(cadena) << ". " << endl;
  14. cout << "\nIntroduce una cadena como puntero: ";
  15. cin >> *pCadena;
  16. cout << "Su tamano es: " << LongitudCadena(pCadena) << ". " << endl;
  17.  
  18. cin.sync();
  19. cin.get();
  20. return 0;
  21. }
  22.  
  23. int LongitudCadena(char *a) {
  24. char *p, *q;
  25. p = a;
  26. q = a;
  27. while (*a) q++;
  28. return q-p;
  29. }

Seguro que hay una forma mucho mas simple, pero aun soy nuevo con esto de los punteros y no los comprendo muy bien. Espero que se pueda encontrar el fallo.

Un saludo.


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: ivancea96 en 15 Septiembre 2014, 17:00 pm
Dado que la 'a' no cambia, "while(*a)" dará bucle infinito.

Puedes poner, en su lugar: "while(*q) ++q;".

Además, si quieres usarlo para otros tipos, deberías poner: "return (q-p)/sizeof(char);". Claro que en este caso, al ser char, no tiene mucho sentido jaja

En todo caso yo quitaría la variable 'p', que sobra. En vez de "return q-p;", poner "return q-a;".


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: Danyfirex en 15 Septiembre 2014, 18:51 pm
Podría ser algo así.


Código
  1. unsigned int Largo(char * ptr){
  2. unsigned int len=0;
  3.  
  4. while (*ptr++)len++;
  5. return len;
  6. }
  7.  

Saludos


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: eferion en 15 Septiembre 2014, 19:09 pm
Podría ser algo así.


Código
  1. unsigned int Largo(char * ptr){
  2. unsigned int len=0;
  3.  
  4. while (*ptr++)len++;
  5. return len;
  6. }
  7.  

Saludos

¿Y la aritmética de punteros donde queda?

Tratando el tema dejado por ivancea96, tal y como está planteado el enunciado no tiene ningún sentido hacer un código más genérico por varias razones:

* Únicamente las cadenas de caracteres tienen la obligación de terminar con caracter nulo.
* La función no admite un segundo parámetro que permita identificar el final de la cadena.

Si se dispusiese de información adicional y de algo más de flexibilidad sería fácil hacer una función genérica que calculase el tamaño de un array cualquiera.



Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: ivancea96 en 15 Septiembre 2014, 19:21 pm
Hablaba para poder portarlo a widechar, por ejemplo. Pero era una mera curiosidad, no digoque sea necesario xD


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: Blaster en 15 Septiembre 2014, 20:08 pm
Seguro que hay una forma mucho mas simple, pero aun soy nuevo con esto de los punteros y no los comprendo muy bien.

Quedaría mas o menos así :

Código
  1. size_t LongitudCadena(const char *str)
  2. {
  3.    const char *s;
  4.    for (s = str; *s; ++s);
  5.    return(s - str);
  6. }

No hay necesidad de usar un segundo puntero

Un Saludo



Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: Bob1098 en 16 Septiembre 2014, 15:32 pm
Vale, muchas gracias a todos por las respuestas. Aunque estoy sea una cosa muy simple me sirve para intentar comprender el funcionamiento de los punteros, ya que según he leído por ahí los punteros usados correctamente son una herramienta muy poderosa.

Un saludo y gracias.


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: rir3760 en 16 Septiembre 2014, 17:15 pm
Otra parte que se debe corregir para que el programa funcione correctamente es:
Código
  1. int main()
  2. {
  3.   char cadena[10];
  4.   char *pCadena = 0;
  5.  
  6.   cout << "Introduce una cadena como array: ";
  7.   cin >> cadena;
  8.   cout << "Su tamano es: " << LongitudCadena(cadena) << ". " << endl;
  9.   cout << "\nIntroduce una cadena como puntero: ";
  10.   cin >> *pCadena;
  11.   cout << "Su tamano es: " << LongitudCadena(pCadena) << ". " << endl;

Ahí el valor inicial de "pCadena" no es valido, hay que cambiarlo a:
Código
  1. int main()
  2. {
  3.   char cadena[10];
  4.   char *pCadena = cadena;
  5.  
  6.   cout << "Introduce una cadena como array: ";
  7.   cin >> cadena;
  8.   cout << "Su tamano es: " << LongitudCadena(cadena) << ". " << endl;
  9.   cout << "\nIntroduce una cadena como puntero: ";
  10.   cin >> pCadena;
  11.   cout << "Su tamano es: " << LongitudCadena(pCadena) << ". " << endl;

Sin embargo no es un buen ejercicio para la practica de punteros por lo siguiente:
1) Cuando se utiliza el operador ">>" con el objeto "cin" (como en tu ejemplo) se lee una palabra y se debe indicar mediante un puntero donde debe almacenarse.
2) Ese puntero se genera de forma automática al utilizar el identificador del array (este es "cadena").

En pocas palabras no hay tal diferencia entre array y puntero en este caso, supongo lo que quiere enseñar el profesor es el uso de los operadores "[]" y "*".

Un saludo


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: Bob1098 en 17 Septiembre 2014, 18:22 pm
Otra parte que se debe corregir para que el programa funcione correctamente es:
Código
  1. int main()
  2. {
  3.   char cadena[10];
  4.   char *pCadena = 0;
  5.  
  6.   cout << "Introduce una cadena como array: ";
  7.   cin >> cadena;
  8.   cout << "Su tamano es: " << LongitudCadena(cadena) << ". " << endl;
  9.   cout << "\nIntroduce una cadena como puntero: ";
  10.   cin >> *pCadena;
  11.   cout << "Su tamano es: " << LongitudCadena(pCadena) << ". " << endl;

Ahí el valor inicial de "pCadena" no es valido, hay que cambiarlo a:
Código
  1. int main()
  2. {
  3.   char cadena[10];
  4.   char *pCadena = cadena;
  5.  
  6.   cout << "Introduce una cadena como array: ";
  7.   cin >> cadena;
  8.   cout << "Su tamano es: " << LongitudCadena(cadena) << ". " << endl;
  9.   cout << "\nIntroduce una cadena como puntero: ";
  10.   cin >> pCadena;
  11.   cout << "Su tamano es: " << LongitudCadena(pCadena) << ". " << endl;

Sin embargo no es un buen ejercicio para la practica de punteros por lo siguiente:
1) Cuando se utiliza el operador ">>" con el objeto "cin" (como en tu ejemplo) se lee una palabra y se debe indicar mediante un puntero donde debe almacenarse.
2) Ese puntero se genera de forma automática al utilizar el identificador del array (este es "cadena").

En pocas palabras no hay tal diferencia entre array y puntero en este caso, supongo lo que quiere enseñar el profesor es el uso de los operadores "[]" y "*".

Un saludo

Vale, ya lo voy pillando. Gracias por la respuesta.

Un saludo


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: do-while en 17 Septiembre 2014, 20:54 pm
¡Buenas!

Esta función es muy sencilla también:
Código
  1. int longitud(char *s)
  2. {
  3.    if(!(*s))
  4.        return 0;
  5.  
  6.    return 1 + longitud(s + 1);
  7. }
  8.  

¡Saludos!

PD: o con un cuerpo de una sola línea: XD
Código
  1. int longitud(char *s)
  2. {
  3.    return (*s) ? 1 + longitud(s + 1) : 0;
  4. }
  5.  


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: Bob1098 en 18 Septiembre 2014, 16:40 pm
¡Buenas!

Esta función es muy sencilla también:
Código
  1. int longitud(char *s)
  2. {
  3.    if(!(*s))
  4.        return 0;
  5.  
  6.    return 1 + longitud(s + 1);
  7. }
  8.  

¡Saludos!

PD: o con un cuerpo de una sola línea: XD
Código
  1. int longitud(char *s)
  2. {
  3.    return (*s) ? 1 + longitud(s + 1) : 0;
  4. }
  5.  

Impresionante, ahora me entero que puedes devolver la función en si jaja. Eso si que es optimizar un código.

Gracias, y un saludo.


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: eferion en 18 Septiembre 2014, 17:14 pm
Eso si que es optimizar un código.

Depende del baremo en que te bases a la hora de definir una optimización:

* Si para ti optimizar es reducir el código de la función, perfecto, esta función es más óptima.
* Si optimizar es sinónimo de velocidad, has de saber que una función recursiva es más lenta que un bucle. Además la recursividad, a diferencia de los bucles, tiene un límite dado por la pila... si te pasas el programa casca.

Con esto no intento desmerecer el ejemplo de do-while, el cual funciona perfectamente, sino comentarte los riesgos de aplicar recursividad a todo.

Además, ten en cuenta que este ejemplo no usa aritmética de punteros.


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: do-while en 20 Septiembre 2014, 18:14 pm
¡Buenas!

Cierto lo que ha dicho eferion. Cuando utilizas una función, y dentro de esta haces una llamada a la misma función estas utilizando recursividad. La recursividad la puedes aplicar cuando tienes un problema del que conoces una solución básica y en el que si no te encuentras en esos "casos base", puedes realizar una llamada a la misma función con unos parámetros que ofrecen una solución más sencilla en cada llamada. Por ejemplo en este caso sé cuando una cadena tiene tamaño cero. Así que si no tengo una cadena sin caracteres, hago una llamada con la cadena que tenía en un principio, pero empezando desde el segundo caracter, y al valor devuelto le tendré que sumar uno por el caracter que he eliminado.

Lo malo de esto es que, como ya te han dicho, puedes llenar la pila del programa. La pila es una parte de la memoria del programa donde se guardan las llamadas a las funciones. Si mal no recuerdo, cuando tu llamas a una función lo primero que haces en la pila es reservar espacio para el valor que devuelve la función. Luego se almacena la dirección de memoria en la que está la siguiente instrucción a la llamada, se reserva espacio para las variables locales de la función y por último se incluye el código de la propia función. Cuando aplicas recursividad, si ésta tiene muchos niveles (muchas llamadas sucesivas a la propia función sin que haya un retorno), puedes llegar a llenar la pila, ya que el proceso descrito se lleva a cabo con cada llamada, y tu programa se detendrá o recibirás algún mensaje de error del sistema o vete tu a saber lo que puede pasar.

¡Saludos!


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: Bob1098 en 5 Septiembre 2015, 23:57 pm
¡Buenas!

Esta función es muy sencilla también:
Código
  1. int longitud(char *s)
  2. {
  3.    if(!(*s))
  4.        return 0;
  5.  
  6.    return 1 + longitud(s + 1);
  7. }
  8.  

¡Saludos!

PD: o con un cuerpo de una sola línea: XD
Código
  1. int longitud(char *s)
  2. {
  3.    return (*s) ? 1 + longitud(s + 1) : 0;
  4. }
  5.  

Me puse a revisar antiguos mensajes y me di cuenta de que no había leído tu respuesta (una lástima por que me parece la función más sencilla y efectiva de todas). Dicho esto, no comprendo muy bien como funciona, solo se que utiliza la recursividad y el if "simplificado". Podrías explicarme un poquito que es lo que hace exactamente?


Título: Re: Calcular longitud de cadena C++ (punteros)
Publicado por: Bob1098 en 5 Septiembre 2015, 23:59 pm
Acabo de comprenderlo, impresionante optimización =D