Sie sind auf Seite 1von 37

Punteros

Introduccin
Los punteros en C constituyen el tema mas
temido por los estudiantes de este lenguaje.
Sin embargo, su concepto, como su
manipulacin son bastante sencillas.
Un puntero no es ms que una variable
esttica cuyo contenido es una direccin de
memoria.

Introduccin
Los punteros en C constituyen el tema mas
temido por los estudiantes de este lenguaje.
Sin embargo, su concepto, como su
manipulacin son bastante sencillas.
Son extremadamente tiles para trabajos
complejos:
Permiten ahorrar espacio en memoria
Reservar dinmicamente memoria
Paso de parmetros por referencia

Cmo se organiza la memoria asociada


a un programa
Como una coleccin de posiciones de
memorias consecutivas. En ellas se almacenan
distintos tipos de datos, por ejemplo
1 char=1 byte
1 int=4 bytes
1 float=4 bytes

Direcciones de Memoria
Al declarar una variable. Por ejemplo: int a;
Estamos reservando espacio en memoria (uno o mas bytes)
Cada byte tiene una direccin. La direccin es un numero
entero, nico para cada byte.
Una variable tiene una direccin en memoria.
Es la direccin del primer byte asignado a la misma
Es imposible predecir que direccin de memoria va a tener una
variable.
Pero si es posible, conocer la direccin que ya se ha asignado

Qu direccin tiene la variable a?


El operador & colocado antes del nombre de la variable, retorna
la direccin de memoria de la misma.

DIRECCIONES DE MEMORIA

Las variables

Si deseamos conocer dicha direccin

Tienen direcciones de memoria


Se usa el operador & de direccin de un objeto en la
memoria

Ejemplo:

int a;
a = 3;
printf(Valor:%d Dir: %d ,a , &a);

La direccin de a se obtiene a travs


de &a y es 1000

Un puntero

Es una variable que puede almacenar direccin de


memoria

1000
1001
1002
1003

&a es
1000
Bytes
usados
por la
variable a

DECLARACION DE PUNTEROS
int *p;

Un tipo de dato
El puntero solo podr almacenar direcciones de
memoria de variables del tipo especificado
Se pueden definir punteros de cualquier tipo:
float *pf;
char *pc;

1000
1001
1002
1003
1004
1005

1000 pt

Un identificador que siempre va antecedido del


operador *
int *pt, x;
pt almacena la
x = 3;
pt = &x;

direccin de x, se dice
que pt apunta a x

Qu son los punteros?


Podemos saber la direccin de una variable usando el operador &
Y.. en que tipo de variable la podemos poner?
En un tipo de variable llamado: puntero
Un puntero es una variable que puede almacenar direcciones de memoria de
otras variables.

Como declaramos un puntero?

1000
1001
1002
1003
1004
1005

int x;
int *pt;
pt almacena la direccin de x,
se dice que pt apunta a x
char *pt2;
1000 pt
pt = &x;
Un puntero se denota por el * antes del nombre de la variable.
pt podr almacenar la direccin de cualquier entero, es un puntero a entero.
A travs de pt podremos acceder a x, pues pt apunta a x.
char *pt2 es un puntero a char, puede almacenar direcciones de variables
tipo char.

Operador contenido
El objetivo de un puntero es poder manipular la
variable a la que apunta.
El operador * se conoce como operador de
contenido.
El operador * ubicado antes de un puntero,
representa a la variable a la que este apunta
Me da el contenido de una posicin de memoria

CONSULTANDO CONTENIDO
Si un puntero apunta a una variable
A travs del puntero se puede llegar a conocer todo sobre la variable
Ejemplo:

char c, *pc1, *pc2;


pc1 = &c;

Si quiero conocer la direccin, uso directamente el puntero


printf(%d, pc1); //Imprimo la dir. Almacenada por pc1
pc2 = pc1; //pc2 almacena la misma dir. que pc1

Si quiero conocer el contenido al que apunta un puntero, uso el


Es equivalente a :
operador *, sobre dicho puntero
printf(%c, c);
c = A
printf(%c, *pc1);
*pc1 = N
printf(%c,c);

Es equivalente a :
c = N

Imprime N pues c ya
cambio

Punteros II
Acceso al contenido de la variable referenciada
printf (%d, *ptr);

// * permite acceso al contenido de radio

int radio;
int *ptr;
radio = 8;
ptr = &radio; // ptr apunta a radio

Ejemplo

printf ("%d \n", radio);


printf ("%d \n", ptr);
printf ("%d \n", *ptr);

*ptr = 32;
printf ("%d \n", radio);
printf ("%d \n", &radio);

Ejercicio en clase
Acceso al contenido de la variable referenciada
int x,y;
-42
17
22
1000
int *p1,*p2;
x = -42;
1004
22
163
y = 163;
1008
1000
1004
0
p1 = &x;
1012
p2 = &y;
1004
0
*p1 = 17;
Es equivalente a escribir
*p2 = x+5;
x = y;
*p1 = *p2;
p1 = p2;

p1 = NULL;
p2 = NULL;

x
y
p1
p2

Esto indica que p1 ahora apunta


a la misma variable que p2
Esto es equivalente a encerar el
puntero, y decir que no apunta a
ninguna variable

PASO DE PARAMETROS
Las funciones son porciones de cdigo
Ejecutan una tarea especifica
Usualmente toman datos de entrada->parmetros
Y retornan un valor

Los parmetros se pueden enviar de dos formas:


Por valor
Por referencia

Paso de Parmetros

Ya que conocemos de funciones, y sabemos crearlas, podemos crear una funcin


que reciba dos valores y los retorne, intercambiados.
Podramos decir que el prototipo sera:

void intercambiar(int a, int b);


void main()
{
int x, y;
printf(Ingrese x:);
scanf(%d,&x);
printf(Ingrese y:);
scanf(%d,&y);
printf(x = %d, y= %d, x, y);
intercambiar(x,y);
printf(x = %d, y= %d, x, y);

Al retornar la funcin no efectuara el


cambio, como lo deseamos. Recordemos
que, al pasar parmetros, se efecta una
copia de los valores. Este tipo de paso de
parmetros se conoce como PASO DE
PARAMETROS POR VALOR.

main
x

a4

3
4

Intercambiar
b

tmp

4
3

}
void intercambiar(int a, int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}

PASO POR VALOR

La funcin no recibe la variable enviada


Recibe una copia
Similar a cuando va al hacer algn tramite y le piden al
cdula
No entrega la cdula verdadera
Entrega una copia
La verdadera estar segura, aunque quemen y destruyan la copia

Ejemplo:
x = 5
printf(%d\n,x);
funct(x);
printf(%d\n,x);
void funct(int y){
y = y+1;
}

Se imprime 5, el valor de x no
cambia aunque la funcin haya
intentado modificarla

Paso de Parmetros por Referencia


Para este tipo de problemas, en los cuales necesitamos modificar
directamente los datos que se reciben como parmetros, se usa la llamada
de parmetros POR REFERENCIA
De esta forma, el prototipo seria:

void intercambiar(int *a, int *b);


Al retornar la funcin si habr
efectuado el cambio sobre las
variables que se pasaron por
referencia.

main
x

3
4

4
3
a

Intercambiar

3
4

tmp

3
4

void main()
{

int x, y;
printf(Ingrese x:);

scanf(%d,&x);
printf(Ingrese y:);
scanf(%d,&y);
printf(x = %d, y= %d, x, y);
intercambiar(&x,&y);
printf(x = %d, y= %d, x, y);
}
void intercambiar(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}

PASO POR REFERENCIA


Aqu si la funcin recibe exactamente la variable
enviada
No hay copias
Si algo se le hace al parmetro, se le esta haciendo a la
variable
Para esto, se usan punteros
La funcin trabaja con un puntero a la variable enviada
Sabe todo sobre esa variable y se pude acceder a travs de *

Ejemplo:

x = 5
printf(%d\n,x);
funct(&x);
printf(%d\n,x);

Se imprime 6, el valor de x cambi


dentro de la funcin

void funct(int *py){


*py = *py+1;
printf(%d\n,*py);
}

Paso por referencia


El paso de parmetros por referencia no debe reemplazar al
paso de parmetros por valor.
Solo se usan parmetros por referencia cuando sea
imperiosamente necesario.
Las funciones, aquellas que retornan valores son:
Fciles de entender y seguir por cualquier programador.
El valor que retornan se puede asignar a una variable.
No as con los procedimientos con valores como referencia.

ARREGLOS
Conjunto de elementos
Finito, Ordenado y Homogneo,
Todos sus elementos son del mismo tipo

Un arreglo esttico se declara


int A[100];
El tipo de los elementos, el identificador y
El numero de elementos (dimensin)

Cada elemento del arreglo tiene un ndice


En C, siempre el ndice mas pequeo es el 0: limite inferior
El limite superior, es 1 menos que la dimensin
Si el arreglo tiene 100 elementos, el ndice mas alto es el 99

Y si un entero ocupa 4 bytes, el arreglo ocupa 400 bytes


seguidos

... 99

OPERACIONES
No basta con la declaracin, para ser tratado como
un tipo de dato
Faltan las operaciones para actuar sobre l
Consulta de un elemento
//Consulto el contenido de los elementos 4 y 5 de A
printf(%d %d,A[4], A[5]);

Modificacin de un elemento
A[3] = 2; //Almaceno un valor en el elemento 3 de A
for(i = 0; i < 100; i++)
A[i] = 0;

REPRESENTACION INTERNA
Cuantos bytes ocupa un tipo de dato o
variable?
En C lo indica el operador sizeof
Ejemplo:
int a;
printf(%d %d, sizeof(int), sizeof(a));

El computador internamente

1000
1008

Lista[1]

1016

Lista[2]

No almacena la direccin de todos los elementos del


arreglo
1024
Solo almacena la direccin del primer elemento
El resto lo calcula as:
1032

&Lista[i]

Lista[0]

-> &Lista[0] + (i*sizeof(Lista[0]))

Lista[3]
Lista[4]

Memoria dinmica
Arreglos dinmicos
Suponga que deseamos crear un programa que almacene
notas de estudiantes, en donde el numero de estudiantes es
desconocido.
Para la nica solucin conocida es tener un arreglo esttico
de un tamao tal que pueda almacenar todas las notas que
suponemos pueda haber.

#define TAM 30;


int notas[TAM];

El nmero mximo
de notas que el
programa puede
almacenar es 30

Y que tal si el
curso contiene 40
estudiantes.
El programa no
servira.

RESERVA DE MEMORIA
DINAMICA

La declaracin de una variable

a no apunta a otra
variable, tiene
memoria propia,
solo para el

Siempre reserva memoria

Aunque la variable no se use, ya se reservo memoria para ella: ESTATICA

Si deseamos reservar memoria, pero no en la declaracin

Si no, a voluntad dentro del programa

La reserva seria dinmica

En C se usan

Punteros y

Las funciones de librera

int *a; //No se reserva nada


..
/*Cuando se desee, se reserva*/
a = malloc(sizeof(int));
//La variable normalmente
*a = 3;

#include <stdlib.h>
void *malloc(size_t size);

Manejo de memoria dinmica


Arreglos dinmicos
La funcin sizeof(TIPO) retorna el tamao en bytes de el
tipo de datos que recibe como parmetro.
La funcin malloc(TAMAO) separa un espacio de memoria
del tamao en bytes que recibe como parmetro y retorna el
puntero a dicho espacio de memoria.
arreglo = malloc(n*sizeof(int));
La funcin free(PUNTERO) libera el espacio de memoria
apuntado por el puntero que se recibe como parmetro.
free(arreglo);

Manejo de memoria dinmica


Arreglos dinmicos
Otra solucin que aprenderemos hoy es crear arreglos dinmicos.
Al usar los arreglos dinmicos, en tiempo de ejecucin se puede
determinar el tamao del arreglo.
Se define el tamao
del arreglo a travs de
la separacin de un
espacio de memoria
que pueda almacenar
los elementos del
arreglo

void main()
{
int *arreglo, n;
printf(Ingrese tamao del arreglo: );
scanf(%d,&n);
arreglo = malloc(n*sizeof(int));
printf(Tiene %d elementos para trabajar\n,n);
free(arreglo);
}

Se define un
puntero al inicio de
un arreglo

Al final se libera el
espacio separado

LIBERAR MEMORIA
Al pedir memoria dinmicamente
Se debe liberar dentro del programa
En C se libera usando la funcin free

int *a;
a = malloc...;

free(a);

Cuando se
libera para
una
variable

Aritmtica de Punteros
Los operadores +(avanzar) y (retroceder)
Se pueden usar con punteros, pero el significado de la operacin cambia un poco

Suponga que un entero ocupa 4 bytes


int x;
int *p;
p = &x;

Suponga que la direccin de x es un valor 100 y decimos


p = p + 2;

La suma indica que p se mueva 2 enteros mas adelante


Cada entero equivale a 4 bytes
100 + 2*4 = 108
31

p2

EJERCICIO EN CLASE
main(){
double Lista[3];
double *p,*p1,*p2;
int k;
Lista[0] = 1;
Lista[1] = 1.1;
Lista[2] = 1.2;
p = Lista;
p = p + 2;
printf(%d, *p);
p = p - 1;
printf(%d, *p);
p1 = Lista+2;
p2 = &Lista[0];
k = p1-p2;
printf(%d, k);
}

1000

Lista[0]

1008
1.1
1016
1.2
p se mueve 2
desfases
p retrocede un
desfase
Da el total de desfases
entre p1 y p2

Lista[1]
Lista[2]

p1

PASO DE ARREGLOS A FUNCIONES


Al pasar un arreglo a una funcin debe tomarse en
cuenta
Necesitare tambin el tamao del arreglo?
Si es as, tambin debe incluirse como parmetro

En prototipos y cabecera
float CalcPromedio(float A[], int size);
float funct(float B[]);

En el cuerpo de la funcin

float CalcPromedio(float A[], int size){


}

..
A[i] = 3;

Siempre recuerde que


El paso de arreglos, es un paso por referencia

ARREGLOS BIDIMENSIONALES
La programacin ofrece innumerables opciones
Un elemento de un arreglo, puede ser otro arreglo
int A[3][3];
A[3] es un arreglo de tres elementos
Cada elemento es otro arreglo de 3 elementos enteros

int A[3][3];
(0,0) (0,1) (0,2)

A[0]

A[0][0] A[0]1] A[0][2]

(1,0) (1,1) (1,2)

A[1]

A[1][0] A[1][1] A[1][2]

(2,0) (2,1) (2,2)

A[2]

A[2][0] A[2][1] A[2][2]

RESUMEN

Relacin con arreglos


Arreglo: Conjunto de registros consecutivos en memoria
int numeros[5];
int numPares[4] = {2, 4, 6, 8};

Espacios para almacenar


enteros consecutivamente

El nombre de un arreglo es SIEMPRE un puntero a su primer elemento


numeros

Cada uno apunta a la direccin del primer entero

numPares

35

RESUMEN

Punteros con memoria propia


Destinos posibles:
1. Apuntar a un espacio de memoria de otra variable
int *a, b = 10;
a = &b; // a no tiene memoria propia, es un ESPEJO de b

2. Solicitar y apuntar a SU PROPIO espacio de memoria


int *a, b = 10;
a = (int*) malloc (sizeof(int));
*a = b; // a almacena en su propio espacio de memoria el valor que b

RESUMEN

Referencias y Funciones
Normalmente, funciones reciben paso de parmetros por valor
La variable en s misma no se enva, se crea una copia

Operador * se usa en funciones de paso por referencia


Permiten cambiar el contenido de una variable externa
El contenido de la variable no se copia (eficiencia)
void miFuncion (int a, int *b)

Das könnte Ihnen auch gefallen