• Martes 24 de Noviembre de 2020, 13:21

Autor Tema:  Ejercicio basico de punteros  (Leído 3802 veces)

Oquindracir

  • Nuevo Miembro
  • *
  • Mensajes: 2
    • Ver Perfil
Ejercicio basico de punteros
« en: Sábado 31 de Agosto de 2013, 06:39 »
0
Hola, buen dia, tengo duda en este ejercicio basico de punteros que se suele poner en algunos libros como una introduccion a los  punteros y al paso por rereferencia. Mi duda no es el programa en si, digamos que mas o menos lo entiendo lo que no alcanzo a comprender del todo, es el papel que juegan los punteros para realizar esta accion. El programa consiste en intercambiar dos valores de dos variables. El programa es el siguiente:

#include <stdio.h>

void change ( int *x, int *y);

void main(void){
    int a = 5, b = 10;

    printf("a = %d b = %d\n", a,b);
    change(&a,&b);
    printf("a = %d b = %d\n", a,b);
}

void change( int *x, int *y){

    int z;

    z = *x;
    *x = *y;
    *y = z;

}
Ademas, ya que el paso por referencia consiste en copiar las lvalue(direcciones de memoria de la variable) a la pila(stack),  ¿porque al declarar las variables "a" y "b" como globales en lugar de locales(como estan el programa), se siguen intercambiando los valores?,  ya que se supone que al no ser variables locales, estas no se almacenan en la pila y por lo tanto el paso por referencia no se logra.


Al hacer la prueba de escritorio, puedo entender perfectamente el programa, lo que no entiendo es ¿porque al no usar punteros no se realiza el intercambio de los datos de la variables?. Este el programa sin punteros, el cual al realizar la prueba de escritorio, me resulta que dichos valores si deberian de ser cambiados.

#include <stdio.h>

void change ( int x, int y);

void main(void){
    int a = 5, b = 10;

    printf("a = %d b = %d\n", a,b);
    change(a,b);
    printf("a = %d b = %d\n", a,b);
   
}

void change( int x, int y){

    int z;

    z = x;
    x = y;
    y = z;

}

El IDE que utilice fue el codeblocks.

Agradecia mucho cualquier ayuda, tips, recomendaciones, etc.

ProfesorX

  • Moderador
  • ******
  • Mensajes: 796
  • Nacionalidad: mx
    • Ver Perfil
Re:Ejercicio basico de punteros
« Respuesta #1 en: Sábado 31 de Agosto de 2013, 19:01 »
0
Hola Oquindracir, bienvenido al foro.

Tratare de responder tus dudas de la mejor manera posible.

Citar
¿porque al declarar las variables "a" y "b" como globales en lugar de locales(como estan el programa), se siguen intercambiando los valores?

Las variables locales tienen preferencia sobre las variables globales, es decir, si tienes 2 variables globales llamadas a y b, y 2 variables locales tambien llamadas a y b, entonces la funcion utilizara las variables locales en lugar de las globales. Esa es una de las razones por la cual no se recomienda el uso de variables globales, porque no sabes si alguna variable local tomara el lugar de una variable global. Quizas en un programa tan corto como este sea facil ver que las variables locales y globales tienen el mismo nombre, pero imaginate si el codigo tuviera miles de lineas de longitud, seria una pesadilla tratar de ver que una variable local no oculte el nombre de una variable global al llamarse igual.

Citar
Al hacer la prueba de escritorio, puedo entender perfectamente el programa, lo que no entiendo es ¿porque al no usar punteros no se realiza el intercambio de los datos de la variables?. Este el programa sin punteros, el cual al realizar la prueba de escritorio, me resulta que dichos valores si deberian de ser cambiados.

Esto es porque, como tu mismo has dicho, las variables locales se crean (copian) en la pila, y al salir de la funcion, ese espacio en la pila queda libre, por lo que, aunque el intercambio dentro de la funcion SI se realiza, estas realizando el intercambio en una COPIA de las variables originales.

Mas claro, supon que tus variables a y b  estan en la direccion 1000 y 1001 respectivamente, y que la pila comienza en la direccion 2000, cuando entras a la funcion y no utilizas punteros, se crean 2 variables en la direccion de pila 2000 y 2001, cuando haces el intercambio, estas intercambiando los valores en la direccion 2000 y 2001, o sea que como dije antes el intercambio si se realiza, pero al salir, las direcciones 2000 y 2001 son liberadas y se pierde el cambio.

Cuando utilizas apuntadores, le estas pasando a la funcion la DIRECCION de a y b, es decir, le pasas como valores 1000 y 1001, entonces cuando realizas el cambio estaras cambiando los valores en las direcciones 1000 y 1001, y no en la direccion 2000 y 2001.

De hecho, la direccion 2000 contendra el valor 1000 y la direccion 2001 contendra el valor 1001, pero esos valores son direcciones y como son direcciones por eso necesitas usar el asterisco (*) para decirle al compilador que no utilice el contenido de la variable como valor, sino cono direccion.

Prueba lo siguiente, imprime x y *x, el primer valor es la direccion que esta contenida en x y el segundo es el valor contenido en la dirreciion x

Código: [Seleccionar]
void change( int *x, int *y)
{

    int z;

    printf("Direccion:%d, Valor:%d\n", x, *x);
    printf("Direccion:%d, Valor:%d\n", y, *y);

    z = *x;
    *x = *y;
    *y = z;
}

Espero que eso aclare tus dudas.

Saludos :)
« última modificación: Sábado 31 de Agosto de 2013, 19:06 por ProfesorX »

NOTA:
==================================================================
Este foro es para ayudar, aprender, compartir... usenlo para eso,
NO SE RESUELVEN DUDAS POR MENSAJE PRIVADO Y MENOS POR CORREO
==================================================================

Oquindracir

  • Nuevo Miembro
  • *
  • Mensajes: 2
    • Ver Perfil
Re:Ejercicio basico de punteros
« Respuesta #2 en: Domingo 1 de Septiembre de 2013, 02:05 »
0
Hola, gracias por responder, solo tengo estas dudas respecto a tu respuesta y son las siguientes: las variables a y b al ser locales  se almacenan en la pila, es decir sus direcciones 1000 y 1001 se encuentran en la pila ¿porque estas variables no se limpian al salir, si tambien forman parte de la pila?

Otra cosa, mi duda respecto al uso de variables globales en lugar de locales, me referia a quiar las variables locales int a = 5 y int b = 10 y declararlas como globales antes del main. Al hacer esto se sigue realizando la misma accion, es decir las variables a y b se intercambian, y es donde surge mi duda que nose porque se realiza esto, ya que  al ser variables globales estas no se almacenan en la pila, entonces ¿como se da el paso por referencia en este caso?

ProfesorX

  • Moderador
  • ******
  • Mensajes: 796
  • Nacionalidad: mx
    • Ver Perfil
Re:Ejercicio basico de punteros
« Respuesta #3 en: Domingo 1 de Septiembre de 2013, 10:22 »
0
Hola Oquindracir, bueno mira, algunos puntos de tu pregunta me parece que ya los habia explicado, aun asi tratare de ser un poco mas especifico a ver si te queda mas claro :)

Citar
las variables a y b al ser locales  se almacenan en la pila, es decir sus direcciones 1000 y 1001 se encuentran en la pila ¿porque estas variables no se limpian al salir, si tambien forman parte de la pila?

Porque cuando sales de una funcion no se borra toda la pila, sino solo la parte o fragmento de la pila que estas utilizando en ese momento, en esa funcion.

Por cuestiones de simplicidad utilice las direcciones 1000, 1001, 2000 y 2001, pero recuerda que no son las verdaderas direcciones, es mas la pila en realidad es una sola area contigua y en realidad no crece hacia arriba, sino que crece hacia abajo. Y metiendonos un poco en lo que es lenguaje maquina no solo se guardan variables, en la pila tambien se guarda la direccion de regreso de la funcion y un registro especial del procesador llamando el Stack Pointer, que nos indica hasta donde crece nuestra pila en determinado momento.

Pero bueno, suponiendo que la pila creciera hacia arriba, si queremos ser mas exactos tus variables locales a y b en main() se guardan en las direciones 1000 y 1001, el compilador genera 2 instrucciones push para guardar a y b, cuando llamas a la funcion change, se guarda la direccion de regreso con otro push en la direccion 1003, cuando estas dentro de change, se generan 3 push, 2 para tus parametros x y y en las direcciones 1004 y 1005, y otro mas para tu variable z en la direccion 1006, cuando llegas al final de la funcion change, el compilador revisa cuantos push se hicieron (3 en este caso) y entonces genera 3 instrucciones pop para eliminar los datos de la pila, regresando el stack pointer a la direccion 1003, luego obtiene de la direccion 1003, la direcion de tu programa donde debe continuar con otro pop, y ahora el stack pointer estara en la posicion 1002. Cuando llega al final del main, el compilador revisa cuantos push hizo (2 en este caso) y ahora hace 2 pop para eliminar los valores 1000 y 1001.

Si dentro de change llamaras a otra funcion con dos parametros, ocurriria lo mismo, el compilador generar 3 push para guardar la direccion de regreso y los dos parametros en las direcciones 1007, 1008 y 1009 respectivamente, si tienes variables locales se guardan en la direcciones siguientes, y al final, el compilador generara tantos pop como push haya hecho.

Citar
Otra cosa, mi duda respecto al uso de variables globales en lugar de locales, me referia a quiar las variables locales int a = 5 y int b = 10 y declararlas como globales antes del main. Al hacer esto se sigue realizando la misma accion, es decir las variables a y b se intercambian, y es donde surge mi duda que nose porque se realiza esto, ya que  al ser variables globales estas no se almacenan en la pila, entonces ¿como se da el paso por referencia en este caso?

Mira, como te dije en mi anterior respuesta, que quizas no leiste bien, aunque tu declares a y b como globales, en el momento que tu le pasas como parametro a change esas variables globales, estaras trabajando con una COPIA, si leelo bien, COPIA, de las variables globales y no con las variables globales originales, y por eso no funcionara, porque sera una COPIA., El intercambio se hara, pero sobre la COPIA, por lo tanto los originales se conservaran sin cambios.

Si deseas que funcione deberas eliminar los parametros, para que puedas usar directamente a y b, SIN GENERAR UNA COPIA.

Prueba lo siguiente:

Código: [Seleccionar]
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#define PI 3.14

int a, b;

// Esta funcion usa parametros sin apuntadores, las variables globales no cambiaran
// Porque internamente a y b se copian a "x" y "y", aunque a y b sean globales
void change1(int x, int y)
{

    int z;

    z = x;
    x = y;
    y = z;
}

// Esta funcion no usa parametros, usa directamente las variables globales, por lo tanto
// los valores si se intercambiaran
void change2()
{

    int z;

    z = a;
    a = b;
    b = z;
}

int main (void)
{
    a = 5, b = 10;

    printf("a = %d b = %d\n", a,b);
    change1(a,b);
    printf("a = %d b = %d\n", a,b);
    change2();
    printf("a = %d b = %d\n", a,b);

    return 0;
}

Mas informacion sobre pilas enlace directo a las pìlas por Hardware (en ingles):
http://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29#Hardware_stacks

Saludos :)
« última modificación: Domingo 1 de Septiembre de 2013, 10:32 por ProfesorX »

NOTA:
==================================================================
Este foro es para ayudar, aprender, compartir... usenlo para eso,
NO SE RESUELVEN DUDAS POR MENSAJE PRIVADO Y MENOS POR CORREO
==================================================================