Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Shout en 23 Julio 2013, 13:35 pm



Título: [Opinión] Interesante manera de usar char* con cout
Publicado por: Shout en 23 Julio 2013, 13:35 pm
Buenas!!

Pues justo hice una función como esta:
Código
  1. void something(char *text){
  2.    cout << *text;
  3. }
  4.  
Y sólo me imprimía text[0].
Suponí que podría ir aumentando el puntero hasta llegar a \0:
Código
  1. void something(char *text){
  2.    while(*text != '\0') cout << *text++;
  3.    // nota: si ponemos *text++ en el while()
  4.    // se salta el caracter 0
  5. }
  6.  
Efectivamente, funciona.

Pero luego pensé en otra manera (sin usar while), y me salió esto:
Código
  1. void something(char **text){
  2.    cout << *text;
  3. }
  4. char *str = "hello world";
  5. something(&str);
  6.  

¿Cuál creéis que es la mejor opción?
La primera, sin duda, es más simple, pero usa while.
La segunda, al ser un poco más complicada, quita legibilidad, pero parece funcionar más rápido.


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: Oblivi0n en 23 Julio 2013, 13:43 pm
Usa cout como siempre.

Imaginate ver 
Código
  1.  while(*text != '\0') cout << *text++;
2 años despues, pensarás que que carajo estás haciendo...


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: amchacon en 23 Julio 2013, 13:44 pm
Código
  1. void something(char **text){
  2.   cout << *text;
  3. }
  4. char *str = "hello world";
  5. something(&str);

Esto es lo mismo que poner:

Código
  1. char *str = "hello world";
  2. cout<<str;


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: Shout en 23 Julio 2013, 13:55 pm
Usa cout como siempre.

Imaginate ver 
Código
  1.  while(*text != '\0') cout << *text++;
2 años despues, pensarás que que carajo estás haciendo...
Tienes razón  :laugh:
Código
  1. void something(char **text){
  2.   cout << *text;
  3. }
  4. char *str = "hello world";
  5. something(&str);

Esto es lo mismo que poner:

Código
  1. char *str = "hello world";
  2. cout<<str;
Lo sé, lo sé.
Mi función creaba una especie de "header" con un montón de opciones, parámetros, FAQ y demás (como quien hace command -h), así que necesitaba envolver eso en una función para no tener que escribirlo cada vez.
Y en ese texto grande tenía que insertar algunas variables.


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: eferion en 23 Julio 2013, 15:10 pm
Es simple...

Código
  1. void something(char *text){
  2.    cout << *text;
  3. }

*text es de tipo char... luego cout solo te imprime un carácter.

Código
  1. void something(char **text){
  2.    cout << *text;
  3. }

*text es de tipo puntero a char... o cadena de caracteres... en este caso vuelca caracteres hasta que se encuentra con el primer nulo.

Código
  1. void something(char *text){
  2.    cout << text;
  3. }

Esta última versión es similar a la anterior sin punteros dobles... y por tanto más usable y manejable.


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: zonahurbana en 24 Julio 2013, 06:46 am
Código
  1. void something(char *text){
  2.    cout << *text;
  3. }

*text es de tipo char... luego cout solo te imprime un carácter.
Cuando se invoca la función y se le pasa como argumento el nombre de un vector de caracteres, realmente se le está pasando la dirección de memoria del primer elemento y por ello sólo muestra el primero, ¿verdad?

Código
  1. void something(char **text){
  2.    cout << *text;
  3. }
Esto es un puntero a otro puntero a char.
Cuando se invoque la función y se le pase como argumento la dirección del primer elemento de un vector de caracteres, dicha dirección de memoria es almacenada en text (variable puntero a puntero). Si escribo *text es como mostrar el valor apuntado por text, que viene a ser un puntero a char. ¿Entonces no debería mostrar la dirección de memoria del vector?

Tal vez puedan explicarme un poco que no lo veo tan simple :S


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: eferion en 24 Julio 2013, 07:11 am
Cuando se invoca la función y se le pasa como argumento el nombre de un vector de caracteres, realmente se le está pasando la dirección de memoria del primer elemento y por ello sólo muestra el primero, ¿verdad?

Si, es cierto, pero la función que recibe un vector de caracteres no se limita a imprimir ese carácter ... la función que recibe un vector de caracteres va a procesar todos los caracteres del vector hasta que encuentre un carácter nulo.

Esto es un puntero a otro puntero a char.
Cuando se invoque la función y se le pase como argumento la dirección del primer elemento de un vector de caracteres, dicha dirección de memoria es almacenada en text (variable puntero a puntero). Si escribo *text es como mostrar el valor apuntado por text, que viene a ser un puntero a char. ¿Entonces no debería mostrar la dirección de memoria del vector?

A ver, cout es una clase de c++. Esta clase tiene varias sobrecargas del operador de inserción ( << ), una para cada tipo de dato soportado.

Cuando a cout se le pasa mediante el operador de inserción un array de caracteres hace exactamente lo que te he comentado, imprimir todos los caracteres que encuentre hasta llegar al primer nulo.

Tu no tienes que mirar las transformaciones que hagas de un dato a la hora de llamar a cout... limítate a ver qué tipo le estás pasando a la clase.

Es decir:

Código
  1. void something(char *text){
  2.    cout << &(*(&(*(&(*text)))));
  3.    cout << text;
  4. }

En ambos casos te va a mostrar una cadena de texto. A la función que recibe el dato únicamente sabe qué tipo le estás pasando, no entiende de las transformaciones previas que le hayas hecho.



Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: Eternal Idol en 24 Julio 2013, 11:09 am
¿Y si usas cout con cadenas de la libreria standard de C++?  :silbar:


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: eferion en 24 Julio 2013, 11:52 am
Te refieres a ...

Código
  1. void something( const std::string& text){
  2.    cout << text;
  3. }

Si es el caso... te va a mostrar la cadena de texto, como es de esperar.


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: Eternal Idol en 24 Julio 2013, 12:00 pm
En realidad era una pregunta retorica.


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: eferion en 24 Julio 2013, 12:03 pm
Perdona, no me dí cuenta de que eras tu... es lo que tiene estar a mil cosas a la vez :)


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: zonahurbana en 24 Julio 2013, 22:58 pm
Si, es cierto, pero la función que recibe un vector de caracteres no se limita a imprimir ese carácter ... la función que recibe un vector de caracteres va a procesar todos los caracteres del vector hasta que encuentre un carácter nulo.
Me estaba refiriendo a lo que decía el autor del tema.

Entonces he escrito lo siguiente:
Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. void something(char *text)
  5. {
  6.    cout << *text;
  7. }
  8.  
  9. int main()
  10. {
  11.    char v[]="Probando";
  12.    cout<<&v<<endl;
  13.    cout<<v<<endl;
  14.    something(v);
  15.    return 0;
  16. }
Y pues, yo creí que pasar como argumento v es lo mismo que pasar &v (pero no es exactamente lo mismo).
Lo primero muestra la dirección de memoria del primer elemento.
Lo segundo imprime toda la cadena como dices.
Pero yo me refería a lo tercero, que sólo muestra el primer caracter (es por el operador de indirección).

Si escribo lo siguiente, sigue mostrando solo la letra 'P':
Código
  1.    char* p = v;
  2.    cout<<*p;
  3.  

Eso quiere decir que cuando a cout le paso v o &v[0] es lo mismo... o incluso si le paso p, pero escribir *p ya le quita la gracia porque muestra el valor del elemento correspondiente a la dirección de memoria (es decir, sólo v[0]).

Entonces podemos decir que v es como un puntero constante a char.
Cuando cout recibe un puntero a char (sea constante o no), muestra el valor apuntado por ese puntero y los valores ubicados en las direcciones de memoria que le siguen, hasta encontrar la marca de fin de cadena.
Pero al escribir &v es como querer obtener la dirección de memoria de algo que ya propiamente es una dirección de memoria y se muestra entonces la dirección de memoria de v[0]. ¿Sería la única forma de mostrar la dirección de memoria de v usando cout?
Si muestro por pantalla &p (donde p es una variable puntero que almacena la dirección de memoria de v[0]) debería pasar lo mismo (pues estoy tratando de obtener la dirección de memoria de una dirección de memoria). Pero al probar esto, la dirección que se muestra es la dirección de la variable puntero, y no se está desreferenciando una dirección de memoria, que es lo que aproximadamente sucede al hacer &v (creo que me estoy haciendo mucho lío en vano :silbar:).

No se me permite hacer algo como:
Código
  1.    p = &v;
Pero sí esto:
Código
  1.    p = &v[0];
  2.    cout<<*p;
  3.  
Y el resultado nuevamente es 'P'.

A ver, cout es una clase de c++. Esta clase tiene varias sobrecargas del operador de inserción ( << ), una para cada tipo de dato soportado.
En realidad cout es un objeto de la clase ostream (o eso es lo que me dice esta referencia (http://www.cplusplus.com/reference/iostream/cout/?kw=cout)).


Y respecto a:
Código
  1. void something(char *text){
  2.    cout<<&(*(&(*(&(*text)))))<<endl;
  3.    cout<<text;
  4. }
En ambos casos te va a mostrar una cadena de texto. A la función que recibe el dato únicamente sabe qué tipo le estás pasando, no entiende de las transformaciones previas que le hayas hecho.
Es porque las transformaciones se hacen previamente y el resultado de dicha expresión es lo que se envía como argumento a cout (ya resuelto), pero eso no implica que yo deba ignorar dichas transformaciones.
Es decir, en este caso se referencia y desreferencia una cantidad igual de veces y luego de hacer todo ello recién muestra lo correspondiente. No es que deba ignorar las transformaciones y fijarme sólo en el tipo de dato que le envío... es decir, si escribiera un & o un * menos, el resultado no sería el mismo (aún cuando las conversiones se estén haciendo sobre un tipo de dato char*).


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: rir3760 en 25 Julio 2013, 17:40 pm
Entonces podemos decir que v es como un puntero constante a char.
Cuando cout recibe un puntero a char (sea constante o no), muestra el valor apuntado por ese puntero y los valores ubicados en las direcciones de memoria que le siguen, hasta encontrar la marca de fin de cadena.

Pero al escribir &v es como querer obtener la dirección de memoria de algo que ya propiamente es una dirección de memoria y se muestra entonces la dirección de memoria de v[0]. ¿Sería la única forma de mostrar la dirección de memoria de v usando cout?

Si muestro por pantalla &p (donde p es una variable puntero que almacena la dirección de memoria de v[0]) debería pasar lo mismo (pues estoy tratando de obtener la dirección de memoria de una dirección de memoria). Pero al probar esto, la dirección que se muestra es la dirección de la variable puntero, y no se está desreferenciando una dirección de memoria, que es lo que aproximadamente sucede al hacer &v (creo que me estoy haciendo mucho lío en vano :silbar:).
Me temo que si.

El punto importante a manejar es: cuando en una expresión se refiere a un array por su nombre (o utilizando una expresión) esto resulta en la dirección en memoria del primer elemento del array, denotar un array de tipo "T [N]" resulta en un puntero de tipo "T *".

El caso usual son las cadenas de caracteres "a la C":
Código
  1. char a[] = "Hola, mundo";
  2. char *p = a;
  3.  
  4. cout << a << endl;
  5. cout << p << endl;
No hay diferencia entre las dos llamadas porque en la primera el uso de "a" genera la dirección en memoria necesaria (de a[0]).

Los dolores de cabeza se pueden generar en los casos donde esa sustitución no se da, por ejemplo cuando el operando de '&' es un array. Ese operador resulta en la dirección en memoria del objeto y si este es de tipo "T" el puntero resultante es de tipo "T *". Aquí:
Código
  1. char a[] = "Hola, mundo";
  2.  
  3. cout <<  a << endl; // 1)  a ==> "char *"
  4. cout << &a << endl; // 2) &a ==> "char (*)[12]"

En el caso 1:
1) El nombre del array resulta en la dirección de su primer elemento.
2) Ya que ese puntero es de tipo "char *" el operador "<<" imprime la cadena de caracteres ahí almacenada.

En el caso 2:
1.1) Primero se procesa "&a", el nombre del array no resulta en un puntero.
1.2) La dirección resultante del operador "&" es de tipo "char (*)[12]".
2) El operando de "<<" es una dirección de memoria pero no es de tipo "char *" y por ende no se procesa como en el caso 1.

Otro caso común es el operador "sizeof".

Un saludo


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: zonahurbana en 25 Julio 2013, 23:43 pm
Los dolores de cabeza se pueden generar en los casos donde esa sustitución no se da, por ejemplo cuando el operando de '&' es un array. Ese operador resulta en la dirección en memoria del objeto y si este es de tipo "T" el puntero resultante es de tipo "T *".
Muchas gracias por responder.
Pero la verdad es que no entiendo mucho a qué se refiere con "dirección en memoria del objeto". Es decir, he revisado los temas de clases y objetos, pero cuando se refiere a un array como objeto, ¿qué debería imaginarme exactamente? ¿Una instancia de una clase que contiene un array?

Agradecería mucho que nos explique un poco más acerca de:
Código
  1. char (*)[12]
O tal vez pueda decirme con qué nombre más o menos buscar este tema.

En este código:
Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main()
  5. {
  6.    char v[]="Probando";
  7.    cout<<v<<endl;
  8.    cout<<&v[0]<<endl;
  9.    cout<<(char*)v<<endl;
  10.    cout<<&v<<endl;
  11.    return 0;
  12. }
Los primeros tres argumentos que se le envían a cout son exactamente lo mismo, ¿verdad?
Es decir, se le envía la dirección en memoria de v[0] y muestra la cadena.
Lo último muestra una dirección de memoria, ¿es la de v[0]?
Antes preguntaba si era la única forma de mostrar por pantalla dicha dirección de memoria.


Título: Re: [Opinión] Interesante manera de usar char* con cout
Publicado por: rir3760 en 26 Julio 2013, 04:09 am
no entiendo mucho a qué se refiere con "dirección en memoria del objeto".
Es la definición mas cruda: un objeto es un pedazo de memoria que se interpreta de acuerdo a su tipo y si tiene nombre se le conoce como variable. La POO es tema aparte.

Agradecería mucho que nos explique un poco más acerca de:
Código
  1. char (*)[12]
O tal vez pueda decirme con qué nombre más o menos buscar este tema.
Es un puntero a array, puedes buscar información sobre arrays, punteros y la relación entre ellos.

En este código:
Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main()
  5. {
  6.    char v[]="Probando";
  7.    cout<<v<<endl;
  8.    cout<<&v[0]<<endl;
  9.    cout<<(char*)v<<endl;
  10.    cout<<&v<<endl;
  11.    return 0;
  12. }
Los primeros tres argumentos que se le envían a cout son exactamente lo mismo, ¿verdad?
Correcto pero, y lo digo en buen plan, eso ya lo había explicado eferion:
Código
  1. &v[0] ==> &(*(v + 0)) ==> &(*(v)) ==> &*v ==> v

Lo último muestra una dirección de memoria, ¿es la de v[0]?
No. Esa es la dirección del array "v" y es de tipo "char (*)[9]" ya que al aplicar el operador "dirección de" sobre un array obtienes un puntero a ... array.

Y si realizas aritmética de punteros este (el puntero) se incrementa un numero de bytes igual al tamaño del array. Por ejemplo:
Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main()
  5. {
  6.   char v[] = "Probando";
  7.  
  8.   cout << "Direccion base: " << (void *) v << endl;
  9.   cout << " v + 2 == " << (void *) ( v + 2) << endl;
  10.   cout << "&v + 2 == " << (void *) (&v + 2) << endl;
  11.  
  12.   return 0;
  13. }

Un saludo