• Sábado 14 de Diciembre de 2024, 15:27

Autor Tema:  ¿que Falla Aqui?  (Leído 2667 veces)

y0mism0

  • Miembro activo
  • **
  • Mensajes: 31
    • Ver Perfil
¿que Falla Aqui?
« en: Lunes 27 de Noviembre de 2006, 08:23 »
0
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef char *Pchar;
typedef char cadena[5];
Pchar devuelve(int);
void main()
{
      printf("%s",devuelve(1));

}

Pchar devuelve(int i)
{
   cadena cad;
   if (i==0)
      strcpy(cad," cero");
   else
      strcpy(cad," uno");
   return cad;
}

Me imprime un simbolo extraño en vez de uno o cero...

Eternal Idol

  • Moderador
  • ******
  • Mensajes: 4696
  • Nacionalidad: ar
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #1 en: Lunes 27 de Noviembre de 2006, 09:30 »
0
Primero un consejo: no uses typedef's totalmente innecesarios, especialmente si queres que otros entiendan tu codigo rapidamente. Usandolos provocas que el codigo no sea directamente comprensible.

Lo que pasa es que esa variable es local y por lo tanto esta en la pila, solo es valida en su ambito, al salir de la funcion la pila es modificada y entonces sus datos ya no corresponden a esos valores que le querias dar (conste que " cero" sobrepasa el tamaño del array, tenes disponibles 4 caracteres mas el 0 que termina la cadena).

Este es el output de un buen compilador como el VC++:
warning C4172: returning address of local variable or temporary

Nacional y Popular En mi país la bandera de Eva es inmortal.


Queremos una Argentina socialmente justa, económicamente libre y  políticamente soberana.
¡Perón cumple, Evita dignifica!


La mano invisible del mercado me robo la billetera.

y0mism0

  • Miembro activo
  • **
  • Mensajes: 31
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #2 en: Martes 28 de Noviembre de 2006, 02:24 »
0
ok, gracias por el consejo.
Alguna explicacion enotnces, para que, si retorno una variable int v; declarada dentro de la funcion y definida con el valor "3", al retornarla por referencia &v al puntero p, si me imprima "3", al desrreferenciar el puntero , *p??

A ver una cosa que no entiendo con el ejemplo de antes retornado cad. Si cad es un una variable de tipo array, digamos que se comporta como un puntero. Entonces digamos que "cad" contiene la direccion de memoria a partir de la cual se almacena el array de caracteres. Por lo que "&cad", seria la direccion de memoria de la propia variable cad de tipo array. Entoces, a mi entender, si tu retornas "cad", estas retornando la direccion de memoria inicial de la cadena. SI tu retornaras esto "&cad", estarias retornando la propia direccion de memoria de la variable cad. La pila, despues de retornar la direccion de memoria inicial de la cadena, osea "cad", se modificaria de tal manera que, ahora, la direccion de memoria de la variable "cad" ya no contendria la direccion de memoria de la cadena, por lo que ya no seria la variable cad. EL caso esque que lo que se destruye al retornar la funcion, es lo que contiene la direccion de memoria de cad, que seria esta "&cad" y no lo que contiene la direccion que apuntaba por cad, osea la cadena, por lo que la direccion de la cadena deberia seguir siendo la misma y contiendo la misma cadena, eso es lo que no entiendo, nose si me explico...

Bueno nose si se entiende lo que quise decir, ahora una pregunta mas secilla :P, por que no se puede retornar "&cad", la direccion de memoria de la variable de tipo cadena? no tienen los punteros tambien su propia direccion de memoria como las variables?

Eternal Idol

  • Moderador
  • ******
  • Mensajes: 4696
  • Nacionalidad: ar
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #3 en: Martes 28 de Noviembre de 2006, 09:18 »
0
Los arrays se pasan siempre por referencia, si retornaras (char*)&cad seria exactamente la misma direccion la que estuvieras devolviendo. No hay una variable que guarde el valor de comienzo del array, no es un puntero.

Código: Text
  1.  
  2. void main()
  3. {
  4.   int *p = devuelve(3);
  5.   devuelve(77);
  6.   printf(&#34;%d&#34;,*p);
  7.  
  8. }
  9.  
  10. int *devuelve(int i)
  11. {
  12.   int v = i;
  13.   return &v;
  14. }
  15.  
  16.  

Eso te imprime 77, el puntero es correcto, pero el valor en la pila es modificado posteriormente.

Nacional y Popular En mi país la bandera de Eva es inmortal.


Queremos una Argentina socialmente justa, económicamente libre y  políticamente soberana.
¡Perón cumple, Evita dignifica!


La mano invisible del mercado me robo la billetera.

y0mism0

  • Miembro activo
  • **
  • Mensajes: 31
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #4 en: Martes 28 de Noviembre de 2006, 13:44 »
0
Citar
Los arrays se pasan siempre por referencia, si retornaras (char*)&cad seria exactamente la misma direccion la que estuvieras devolviendo.
Que es el (char*)? porque hace falta ponerlo?

Citar
Eso te imprime 77, el puntero es correcto, pero el valor en la pila es modificado posteriormente.
Pues no entiendo la diferencia entre retornar "cad" y retornar "&v", ambas son direcciones de memoria, y ambas son modificadas al retornar la funcion, por lo que tambien tendria que variar el contenido de "&v"... incluso el compilador te marca el mismo aviso que dijiste "warning C4172: returning address of local variable or temporary".

Otra cosa, que estas comparando en esta sentencia? : "if(cad1<cad2)"... ya se que para comparar se utiliza strcmp...

Eternal Idol

  • Moderador
  • ******
  • Mensajes: 4696
  • Nacionalidad: ar
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #5 en: Martes 28 de Noviembre de 2006, 13:58 »
0
Cita de: "y0mism0"
Que es el (char*)? porque hace falta ponerlo?

Es un casting, hace falta ya que tu variable es char[5] y no char *.

Cita de: "y0mism0"
Pues no entiendo la diferencia entre retornar "cad" y retornar "&v", ambas son direcciones de memoria, y ambas son modificadas al retornar la funcion, por lo que tambien tendria que variar el contenido de "&v"... incluso el compilador te marca el mismo aviso que dijiste "warning C4172: returning address of local variable or temporary".

No hay diferencia, las dos estan mal, vos dijiste que funcionaba y yo te mostre que en ese caso durante un momento funcionaba y ni bien hacias una operacion el valor, que esta en la pila, era modificado. El contenido de v varia, por algo imprime 77 y no 3, v sigue apuntando a la misma direccion en memoria pero su contenido cambia.

Cita de: "y0mism0"
Otra cosa, que estas comparando en esta sentencia? : "if(cad1<cad2)"... ya se que para comparar se utiliza strcmp...

No se de donde salio eso pero estarias comparando las direcciones en memoria.

Nacional y Popular En mi país la bandera de Eva es inmortal.


Queremos una Argentina socialmente justa, económicamente libre y  políticamente soberana.
¡Perón cumple, Evita dignifica!


La mano invisible del mercado me robo la billetera.

y0mism0

  • Miembro activo
  • **
  • Mensajes: 31
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #6 en: Miércoles 29 de Noviembre de 2006, 01:52 »
0
Citar
Es un casting, hace falta ya que tu variable es char[5] y no char *.
Porque tiene que ser "char*"? no estabamos devolviendo antes cad? que deberia ser lo mismo que &cad?



Citar
No hay diferencia, las dos estan mal, vos dijiste que funcionaba y yo te mostre que en ese caso durante un momento funcionaba y ni bien hacias una operacion el valor, que esta en la pila, era modificado. El contenido de v varia, por algo imprime 77 y no 3, v sigue apuntando a la misma direccion en memoria pero su contenido cambia.

Pero cambia, porque invocaste a la funcion primero con 3 y luego con 77, entonces logicamente, la direccion de memoria de v contendra el ultimo valor que le diste, en este caso 77, y te imprime de hecho 77. Pero en el caso que yo puse arriba, invoque a la funcion solo con un valor, solo una vez, y sin embargo, la pila es modificada mientras que con "&v" no.

y0mism0

  • Miembro activo
  • **
  • Mensajes: 31
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #7 en: Miércoles 29 de Noviembre de 2006, 09:35 »
0
Ya lo hice, gracias por tu ayuda. A ver, si yo el ejemplo que me pusiste lo entiendo, entiendo lo que quieres decir, el puntero modifica su valor apuntado cada vez que algo llama a la funcion...
Yo solo me refiero al primer ejemplo, al de la cadena. Mas facil aún :
Código: Text
  1. #include&#60;stdio.h&#62;
  2. char* funcion(int);
  3. void main()
  4. {
  5. char* a=funcion(8);
  6. printf(&#34;%c&#34;,a);
  7. }
  8. char *funcion(int a){
  9.   char cad[20]=&#34;hola&#34;;
  10.   return cad;
  11. }
  12.  

Aqui me imprime caracteres extraños, pero sin embargo si imprimo los caracteres uno a uno, no :
Código: Text
  1. #include&#60;stdio.h&#62;
  2. char* funcion(int);
  3. void main()
  4. {
  5. char* a=funcion(8);
  6. printf(&#34;%c&#34;,a[2]);
  7. }
  8. char *funcion(int a){
  9.   char cad[20]=&#34;hola&#34;;
  10.   return cad;
  11. }
  12.  
Aqui me imprime "l", o sea que esta bien. Realmente lo unico que no entiendo es porque al intentar imprimir la cadena entera, no se imprime, y si la intento imprimir caracter a caracter, si...

Eternal Idol

  • Moderador
  • ******
  • Mensajes: 4696
  • Nacionalidad: ar
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #8 en: Miércoles 29 de Noviembre de 2006, 09:38 »
0
Cita de: "y0mism0"
Porque tiene que ser "char*"? no estabamos devolviendo antes cad? que deberia ser lo mismo que &cad?

cad es char[5] y &cad es char(*)[5], char[5] es convertido automaticamente a char*.

Cita de: "y0mism0"
Pero cambia, porque invocaste a la funcion primero con 3 y luego con 77, entonces logicamente, la direccion de memoria de v contendra el ultimo valor que le diste, en este caso 77, y te imprime de hecho 77. Pero en el caso que yo puse arriba, invoque a la funcion solo con un valor, solo una vez, y sin embargo, la pila es modificada mientras que con "&v" no.

Las variables LOCALES tienen un ambito restringido a la funcion, eso viene en cualquier libro de C basico. Este tipo de variables usa la pila y el punto es que la pila es totalmente volatil, no podes usarla, no tiene importancia que durante un X tiempo tu valor sea valido ya que no sabes si lo seguira siendo y lo mas probable es que NO lo sea.

En tu caso es la funcion printf la que cambia el valor, al entrar y poner tres registros en la pila (ebx, esi y edi). En el caso del int si funciona ya que a printf se le pasa directamente el VALOR y no un puntero al valor. Todo esto se ve muy claramente si depuras el programa:

Código: Text
  1.  
  2. #include&#60;stdio.h&#62;
  3. #include&#60;string.h&#62;
  4. #include&#60;stdlib.h&#62;
  5. typedef char *Pchar;
  6. typedef char cadena[5];
  7. Pchar devuelve(int);
  8. int *dame(int);
  9.  
  10. void main()
  11. {
  12.   printf(&#34;%s&#34;,devuelve(1));
  13.   printf(&#34;%d&#092;r&#092;n&#34;, *dame(3));
  14. }
  15.  
  16. int *dame(int t)
  17. {
  18.   int x = t;
  19.   return &x;
  20. }
  21.  
  22.  
  23. Pchar devuelve(int i)
  24. {
  25. cadena cad;
  26. if (i==0)
  27. strcpy(cad,&#34; cero&#34;);
  28. else
  29. strcpy(cad,&#34; uno&#34;);
  30. return cad;
  31. }
  32.  
  33.  

En el caso de devuelve pasa esto:
Código: Text
  1.  
  2. push 1
  3. call devuelve
  4. add esp, 4&#59;arregla la pila
  5. push eax&#59;en eax esta la direccion de memoria devuelta por devuelve
  6. push offset &#036;SG1245&#59;&#34;%s&#34;
  7. call _printf
  8.  
  9.  

Al entrar printf modifica la pila.

En el caso de dame pasa esto:
Código: Text
  1.  
  2. push 3
  3. call dame
  4. add esp, 4&#59;arregla la pila
  5. ;en este punto eax es la direccion de memoria devuelta por dame
  6. mov eax,dword ptr [eax]
  7. ;ahora es el valor contenido por esa direccion de memoria
  8. push eax&#59;que es pasada como parametro aca
  9. push offset &#036;SG1246&#59;&#34;%d&#34;
  10. call _printf
  11.  
  12.  

Entonces no importa si el contenido de la direccion de memoria varia ya que %d es pasado por valor.

Nacional y Popular En mi país la bandera de Eva es inmortal.


Queremos una Argentina socialmente justa, económicamente libre y  políticamente soberana.
¡Perón cumple, Evita dignifica!


La mano invisible del mercado me robo la billetera.

Eternal Idol

  • Moderador
  • ******
  • Mensajes: 4696
  • Nacionalidad: ar
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #9 en: Miércoles 29 de Noviembre de 2006, 09:40 »
0
Cita de: "y0mism0"
Ya lo hice, gracias por tu ayuda. A ver, si yo el ejemplo que me pusiste lo entiendo, entiendo lo que quieres decir, el puntero modifica su valor apuntado cada vez que algo llama a la funcion...
Lo mismo que en el caso de int, char se pasa por valor y no por referencia.

Nacional y Popular En mi país la bandera de Eva es inmortal.


Queremos una Argentina socialmente justa, económicamente libre y  políticamente soberana.
¡Perón cumple, Evita dignifica!


La mano invisible del mercado me robo la billetera.

y0mism0

  • Miembro activo
  • **
  • Mensajes: 31
    • Ver Perfil
Re: ¿que Falla Aqui?
« Respuesta #10 en: Jueves 30 de Noviembre de 2006, 02:15 »
0
ok, entendido, buena explicación, gracias ;)