Foros del Web » Programación para mayores de 30 ;) » Programación General »

Enrredada con Punteros

Estas en el tema de Enrredada con Punteros en el foro de Programación General en Foros del Web. Hola, No puedo comprender los punteros (&,*) por mas que leo y leo no entiendo claro como son. Alguien podria darme una breve explicacion facil ...
  #1 (permalink)  
Antiguo 23/10/2004, 09:51
 
Fecha de Ingreso: octubre-2004
Mensajes: 11
Antigüedad: 20 años, 1 mes
Puntos: 0
Enrredada con Punteros

Hola,
No puedo comprender los punteros (&,*)
por mas que leo y leo no entiendo claro como son.

Alguien podria darme una breve explicacion facil de entender?

Segun entiendo el (&) encuentra la direccion y (*) agarra el valor?

gracias
  #2 (permalink)  
Antiguo 23/10/2004, 13:42
 
Fecha de Ingreso: marzo-2002
Ubicación: Salta Capital - Actualmente estudiando en Córdoba
Mensajes: 430
Antigüedad: 22 años, 8 meses
Puntos: 0
Hola que tal, con respecto a los punteros, el * es un puntero que apunta a una direccion de memoria y el & se usa para pasar las cosas por referencia, o mas bien para modificar el contenido de esa direccion de memoria.
Por ejemplo, no se si conoces las listas, bueno cuando vas creano una lista, declaras un puntero que va a apuntar a una direccion de memoria, y a otra y a otra segun cuantos elementos tengas en la lista, ahora bien, si tuvieras que hacer un recorrido, y modificar en el camino algun elemento de esa lista ya sea actualizarlo o eliminarlo, entonces tendras que usar el puntero de esta forma *&nombre permitiendo en este caso modificar la direccion de memoria y el contenido.
Basicamente, tene en cuenta esto:
El puntero * lo usas para apuntar a una direccion de memoria y lo usas de solo lectura.
El puntero & lo usas para modificar los contenidos en la memoria, elminar registros, etc.

Bueno espero que mas o menos te haya servido la explicacion y si alguien puede colaborar con esto les agradeceria, ya que es un tema muy importante y que tiene que ser bien asimilado para lograr buenos programas y hacer lo que uno quiera con esta herramienta que es tan potente.
Si me llegase a haber confundido por favor corrijanme. Por lo menos eso es lo que vimos en la facultad la semana pasada.
Un abrazo
__________________
Nada es imposible, con un poco de esfuerzo se logran las cosas.-
  #3 (permalink)  
Antiguo 23/10/2004, 13:45
 
Fecha de Ingreso: marzo-2002
Ubicación: Salta Capital - Actualmente estudiando en Córdoba
Mensajes: 430
Antigüedad: 22 años, 8 meses
Puntos: 0
Me olvidaba, mirá esta página tiene curso sobre C++ y sobre las Apis para programar para windows.
Esta bastante bueno con ejemplos y codigos fuentes para bajar.

http://c.conclase.net
__________________
Nada es imposible, con un poco de esfuerzo se logran las cosas.-
  #4 (permalink)  
Antiguo 23/10/2004, 18:34
 
Fecha de Ingreso: octubre-2004
Mensajes: 11
Antigüedad: 20 años, 1 mes
Puntos: 0
Gracias.
Desde que puse el tema asta esta hora he estado estudiando los punteros, con lo que me dices y con lo que he visto llego a esta conclusión:

cada variable tiene un domicilio en la memoria, entonces los punteros hacienden a ese domicilio y pueden cambiar el valor que hay en esa variable.

Ejemplo que me hice como de primaria jeje

Si Variable de nombre “a” vive en la casa numero 16 (dirección de memoria) y La variable “b” vive en la casa 18 entonces continuamos así:
declarando dos punteros

int *pun, * pun1

Hora usamos el puntero para darle valor a variable a y b (claro que si lla tienen valor pues ya nimodo)

pun = &a // ahora pun tiene el domicilio de "a" (casa numero 16)
*pun = 3 // ahora "a" vale 3
pun1 = &b // ahora pun1 tiene el domicilio de "b" (casa 18)
*pun1 = 5 // ahora "b" vale 5

Hora modificamos cosillas
Pun = pun1 // creo que aquí pun toma el domicilio de "b" (me equivoco?)

Ya me confundi jeje al rato en la noche modifico y agrego cosas.

Bueno el caso es que voy comprendiendo un poco, y con lo de la lista que me dices ya me da mas sentido para que usarlos, por que yo creo que no es lo mismo aprender una formula a saber en que usarla. Eso me pasa mucho en programación.

Gracias de nuevo y corríjanme en lo que puse porfa

Última edición por coco129; 23/10/2004 a las 18:37
  #5 (permalink)  
Antiguo 23/10/2004, 20:00
Avatar de KnowDemon  
Fecha de Ingreso: julio-2004
Ubicación: Ciudad de México
Mensajes: 544
Antigüedad: 20 años, 4 meses
Puntos: 2
Hay que tratar de ser un poco más riguroso con el lenguaje pues nos puede llevar a confusión. Veamos:

Los punteros SON VARIABLES que almacenan direcciones de memoria al tipo de dato especificado.

int *puntero;

En una variable tipo "puntero a entero"

El símbolo & es el OPERADOR MONÁDICO, que devuelve la dirección de memoria de una variable (la que sea).

El simbolo * es el OPERADOR DE INDIRECCIÓN que devuelve el contenido de una variable apuntada por un apuntador.

Es decir, siguiendo con el código anterior, si yo escribo:

puntero = &a;

La variable puntero almacena la dirección de la variable a.

Ahora:

b = *puntero;

La variable b toma el valor de la variable a la que apunta puntero.

*puntero = b;

La variable a la que apunta puntero toma el valor de b.

puntero1 = puntero2;

Ya que los punteros son variables y almacenan direcciones, la instrucción anterior copiará el contenido de puntero2 a puntero1. (La dirección que almacena puntero2 también la almacenará puntero1)

El siguiente código utiliza un puntero a puntero:

#include <stdio.h>

int main()
{
int a, *puntero, **puntero_a_puntero;

a = 10; //a toma el valor de 10
puntero = &a; //puntero toma la dirección de a
puntero_a_puntero = &puntero; //puntero_a_puntero toma la dirección de puntero

//Se imprime el contenido de lo que apunta aquello a lo que apunta puntero_a_puntero

printf("El valor de a es: %d", **puntero_a_puntero);

getchar();

return(0);
}
__________________
Mi pequeño espacio en la web: VisiónE
"El cosmos es todo lo que es, todo lo que fue, y todo lo que será alguna vez."

Última edición por KnowDemon; 23/10/2004 a las 20:25
  #6 (permalink)  
Antiguo 23/10/2004, 21:54
 
Fecha de Ingreso: octubre-2004
Mensajes: 11
Antigüedad: 20 años, 1 mes
Puntos: 0
Tnx KnowDemon compile el ejemplo e imprime 10
Ya comprendo mas de el tema, pero tengo una preocupacion y seria como usarlos en que ocaciones etc

No tendrias un ejersicio o algun ejemplo para asi comprender mas afondo

Creo que para continuar con el manual y pasar a Vectores, etc tengo que comprender bien punteros verdad

Bueno gracias pues, ya la llevo adelante
  #7 (permalink)  
Antiguo 24/10/2004, 04:56
Avatar de Beakdan  
Fecha de Ingreso: diciembre-2001
Ubicación: Monterrey, Nuevo León
Mensajes: 433
Antigüedad: 23 años
Puntos: 7
Coco129:
Esto que a contnuación voy a poner, es una adaptación de un "cursillo" que doy sobre microcontroladores programados con lenguaje C. Según mi opinión, es más fácil comprender un concepto si pudes visualizarlo. KnowDemon te ha dado una buena explicación acerca de los conceptos, así que trataré de complementarlo un poco.
Sea dado el siguiente fragmento de código:
Código:
#include <stdio.h>
int main(){
	unsigned int X = 0x4847463B;
	unsigned int Y = 0x44434241;
	unsigned int *pToInt = &X;
	char szCita[] = "En un lugar de la..";
	char *pToChar = szCita;
	unsigned int i = 0;
	...
Ignoremos por el momento lo que seguiría a continuación de las declaraciones de las anteriores variables, y veamos que pasa en memoria:


La anterior imagen representa como se acomodarían las variables en el stack para poder ser utilizadas a partir de una dirección ficticia (FF60), la línea inferior del grafico es sólo para dar idea de como se van acomodando los bytes y como va el conteo de los mismos. Según el compilador que uses, puede haber variaciones en el acomodo, pero ignoremos eso por el momento. Aclaro además, que en los procesadores x86, el stack crece hacia abajo (por ridícula que suene la expresón).
Lo importante aquí, es que se acomodan en el orden en que han sido declaradas. Ahora, nos interesa en particular pToInt. Esta variable ha sido declarada como un puntero a un integer, y ha sido inicializada con la dirección de la variable X.
La variable X, está en la dirección FF60. Por lo tanto, el valor almacenado en pToInt es 0x0000FF60.
Znet comentaba que un puntero "lo usas de solo lectura". Pero un puntero es al fin y al cabo una variable. Y para ser exactos es una variable de tipo integer (en procesadores de 32 bits). Por lo tanto, en un puntero se pueden realizar operaciones como se haría con cualquier otra variable numérica.
¿Que pasaría con la sentencia "pToChar++"? Nota que no estoy usando el operador de indirección.
Simplemente accederiamos a la siguiente posición de memoria.
Código:
	//Hasta 18, ya que sólo tenemos 19 caracteres y un null
	for(i=0; i<=18; i++){
		printf("%c", *(pToChar++));
	}
 
	//O también
	for(i=0; i<=18; i++){
		printf("%c", *(pToChar + i));
	}
	//Ambas sentencias equivalen a
	for(i=0; i<=18; i++){
		printf("%c", szCita[i]);
	}
¿Que pasaría con la sentencia "pToInt--"?
Puesto que ahora contiene el valor 0x0000FF60, después de la operación pToInt--, pToInt contendrá 0x0000FF5C. ¡Un momento! ¡Pero si sólo lo decrementamos en 1! La diferencia entre FF60 y FF5C es de 4 ¿qué pasó?
Es probable que hayas leído en algún libro de C, o tal vez en clases habrás oído que un puntero declarado para cierto tipo de dato, sólo puede apuntar a variables del mismo tipo de dato. Por ejemplo un puntero de tipo char no puede apuntar a una variable integer. ¿Pero por qué? Porque cuando el programa se compila, a nivel de procesador, el puntero es una variable que es referenciada con un offset fijo. Un puntero de tipo Integer, solo referenciará posiciones de memoria multiplos de 4, un puntero de tipo short integer multiplos de 2, un puntero de tipo char podrá referenciar cualquier posición de memoria. Pero independientemente de ello, todos ocuparan la misma cantidad de memoria.
Entonces, la sentencia "pToInt--" podría ser interpretada como "asignar a pToInt la dirección del integer inmediatamente inferior al que actualmente apunta".
Hagamos ahora algo que pondría los pelos de punta a mi antiguo maestro de programación. Asignemos a un puntero de tipo integer, la dirección de memoria de un char.
¿Qué no se puede? ¡Por supuesto que sí! ¿Qué para que querría hacer alguien semejante cosa? Es cuestión de la imaginación de cada loco, pero por lo menos, en la programación de microcontroladores, esto me ha sacado más de una vez de apuros. Y también lo he usado en programación de Windows, para ahorrarme trabajo. Y ahora lo haremos sólo para demostrar cuán poderosos pueden ser los punteros.
Puesto que los punteros, independientemente del tipo de dato al que apunten son del mismo tamaño, la siguiente sentencia es perfectamente válida.
pToInt = (unsigned int *) szCita;
¿Qué acabamos de hacer? Acabamos de lograr que el espacio definido en memoria como char, se comporte como integer. Si trazamos el valor, veremos que en Hexadecimal equivale a 0x75206E45, que resultan ser los primeros cuatro caracteres de nuestra cadena.
Ya que estamos "encarrerados", asignemos a un puntero de tipo char una variable de tipo integer. Pero elevemos la emoción un grado más. Vamos a obtener e imprimir la cadena de caracteres que está contenida en las variables X e Y. Los numeros contenidos en dichas variables no han sido declarados de manera casual. X contiene el equivalente en memoria de ['H','G','F',';'] e Y el equivalente de ['D','C','B','A']
Código:
	pToInt = &Y
	*pToInt += 10;
	pToChar = (char *) &Y;
	for(i=0; i<=7; i++){
		printf("%c", *(pToChar + i));
	}
Lo anterior imprimira en pantalla, "ABCDEFGH"

A continuación te dejo un pequeño código con los experimentos que arriba meciono. Espero que no te haya confundido, y que esto no haya sdo aburrido. Pero la verdad es que creo que nadie comprende realmente los punteros hasta que aprende algo de ensamblador. Bueno, es sólo mi opinión.
Código:
#include <stdio.h>
int main(){
using namespace std;
	unsigned int X = 0x4847463B;
	unsigned int Y = 0x44434241;
	unsigned int *pToInt = &X;
	char szCita[] = "En un lugar de la..";
	char *pToChar = szCita;
	unsigned int i = 0;
 
	//Mostramos los valores
	printf("X = %d \n", X);
	printf("Y = %d \n", Y);
	printf("szCita = %s \n\n\n", szCita);
 
	//Apuntadores de la variables
	printf("Addr de X es: %d \n", &X);
	printf("Addr de Y es: %d \n", &Y);
	printf("Addr de pToInt es: %d \n", &pToInt);
	printf("Addr de szCita es: %d \n", szCita);
	printf("Addr de pToChar es: %d \n", &pToChar);
	printf("Addr de i es: %d \n\n\n", &i);
 
	//Operaciones sobre X mediante el puntero
	printf("Valor de X mediante *pToInt\n");
	printf("*pToInt = %d \n\n", *pToInt);
	printf("Aumentamos el valor de X mediante *pToInt\n");
	printf("X = %d\n", X);
	printf("*pToInt+=10\n");
	*pToInt+=10;
	printf("X = %d\n\n\n", X);
 
	/*
Decrementamos el valor del puntero. No el valor de la variable
referenciada, sino el valor de la dirección almacenada en el
puntero. Esto es algo catalogado como "peligroso", pero si se
sabe lo que se está haciendo puede ser útil en algunas situaciones.
En este caso, sabemos que las variables X e Y están colocadas en
posiciones adyacentes de la memoria, y puesto que pToInt apunta a
X, decrementarlo en 1, hará que apunte ahora a Y.
*/
	pToInt--;
	//Operaciones sobre Y mediante el puntero
	printf("Valor de Y mediante *pToInt\n");
	printf("*pToInt = %d \n\n\n", *pToInt);
 
	//Operaciones sobre el string de modo normal
printf("Imprimimos el contenido del string iterando\n");
printf("en cada uno de sus elementos...\n");
	for(i=0; i<=18; i++){
		printf("%c", szCita[i]);
	}
	printf("\n\n");
 
	//Operaciones sobre el string con el puntero
printf("Imprimimos el contenido del string incrementando\n");
printf("el valor del puntero pToChar...\n");
	for(i=0; i<=18; i++){
 
printf("%c", *(pToChar++));
		//printf("%c", *(pToChar + i));
	}
	printf("\n\n\n");
 
/*
Asignar un puntero de un tipo a otro de tipo distinto,
es algo "peligroso", pero perfectamente posible.
*/
//Dirección de un integer a un puntero de tipo char	
	pToChar = (char *) &Y; //Usamos casting para que se pueda compilar
	for(i=0; i<=7; i++){
		printf("%c", *(pToChar + i));
	}
	printf("\n\n\n");
	//Direccion de la cadena a un puntero de tipo integer
	pToInt = (unsigned int *) szCita;
	printf("Hex: 0x%x \n", *pToInt);
 
	getchar();
return 0;
}

Última edición por Beakdan; 24/10/2004 a las 05:00
  #8 (permalink)  
Antiguo 24/10/2004, 09:13
 
Fecha de Ingreso: octubre-2004
Mensajes: 11
Antigüedad: 20 años, 1 mes
Puntos: 0
No, para nada, no esta aburrido al contrario muy interesante lo que has puesto, y muchas gracias por tomarte el tiempo de ponerlo.

Con lo que me has dado creo que tengo material para el día de hoy y estudiar al respecto, algo que me dijeron mucho amigos estudiantes es que no me preocupara de direcciones de memoria ni de números en hex... pero ahora veo que están equivocados pues si es necesario para poder comprender bien el tema.

Gracias de nuevo y mañana te digo que no comprendí, necesito revisarlo bien para asimilar correcta mente. (ya tengo días con pesadillas por los punteros )
  #9 (permalink)  
Antiguo 24/10/2004, 13:22
Avatar de KnowDemon  
Fecha de Ingreso: julio-2004
Ubicación: Ciudad de México
Mensajes: 544
Antigüedad: 20 años, 4 meses
Puntos: 2
¿Recuerdas que dijimos que el apuntador almacena la dirección de una variable? Haré una correción y diré simplemente que almacena una dirección. ¿Por qué?, por que puede almacenar una dirección que no pertenezca a ninguna variable.

Los punteros son ideales para la asignación dinámica de memoria. En tiempo de ejecución puedes "crear" y "destruir" variables. En C puedes hacer algo como esto:

#include <stdio.h>
#include <stdlib.h>

int main()
{
int *dinamic; //Declaro un apuntador a entero

//Reservo un espacio de memoria del tamaño de un entero, si se consigue,
//dinamic apuntara a dicha dirección de memoria:
dinamic = (int *)malloc(sizeof(int));

*dinamic = 99; //Asigno a ese espacio de memoria el valor de 99

printf("El valor de lo que apunta dinamic es: %d", *dinamic); //Lo imprimo

free(dinamic); //Libero la memoria previamente reservada

getchar();

return(0);
}



Aquí puedes encontrar un sencillo manual de C que habla de apuntadores, estructuras dinámicas, etc:
__________________
Mi pequeño espacio en la web: VisiónE
"El cosmos es todo lo que es, todo lo que fue, y todo lo que será alguna vez."

Última edición por KnowDemon; 25/10/2004 a las 01:48
  #10 (permalink)  
Antiguo 24/10/2004, 13:24
Avatar de Beakdan  
Fecha de Ingreso: diciembre-2001
Ubicación: Monterrey, Nuevo León
Mensajes: 433
Antigüedad: 23 años
Puntos: 7
Coco129
Puse los valores en hexadecimal, por mero hábito. No es realmente necesario, pero, es más fácil escribir un hexadecimal, que intentar colocar su representación decimal cuando estamos hablando de memoria y punteros.
En, fin, si puedo ayudarte con algo más...

Hasta luego.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 03:10.