Sunteți pe pagina 1din 55

Lenguaje C

Por qu punteros ahora?

Despus de todo, hablar de Lenguaje C es casi como hablar de


punteros. Esta en todas partes del lenguaje y esta en todas sus
libreras estndar. Casi todo tiene que ver con ellos de una u otra
forma. Y por desgracia, se requiere buena disciplina para usarlos.

Todo programador novato se ha roto la cabeza intentando explicarse


porque un simple printf termina en una violacin de segmento o
porque no compila su programa y se soluciona colocando caracteres
extraos como & y *

Estoy convencido que mientras ms rpido usemos los punteros, ms


rpido aprenderemos el lenguaje C y menos errores sin sentido nos
agobiaran al programar. Conocer lo que hace a este lenguaje tan
poderoso sin duda nos dar la mejor de las ventajas
Lenguaje C

MAXIMA: Sin
punteros no hay
paraso
Lenguaje C

SCRIPT II

Punteros
en C
Lenguaje C

Script II Punteros en C

>> Repasando las Variables


>> Usando Variables
>> Los operadores & y *&
>> Qu es un puntero
>> Puntero Endemoniado
>> Tipos de datos bsicos para punteros
>> Asignacin de punteros
>> Funciones en C
>> Paso de punteros a funciones
>> Punteros y Arrays
>> Punteros y Cadenas
>> Arrays de Punteros
>> Punteros a Punteros
>> Punteros NULL y VOID
>> Punteros constantes
>> Punteros a funciones
>> Callbacks
>> Bonus Track - Recomendaciones
Lenguaje C

REPASANDO LAS
VARIABLES
int
Como ya sabemos, las variables en
el lenguaje C tienen 5 elementos 32 bits
que debemos tener presente: edad
1. Nombre de la Variable 10
2.Tipo de Dato
3.Tamao
4.Valor
5.Direccin de Memoria 0xf0113b1
Para comprender el uso de
punteros es indispensable conocer
el uso de las variables. Un error
muy comn es desconocer la
relacin entre estos elementos y
Lenguaje C

REPASANDO LAS
VARIABLES
int
Para empezar a utilizar punteros en
C, debemos prestar especial 32 bits
atencin a las direcciones de
memoria.
edad
10
Aunque parezca mentira, y a pesar
de que casi no las miramos, las
direcciones de memoria son la
clave para entender las bases del 0xf0113b1
uso de punteros. Saber usar una
direccin de memoria y el valor de
una direccin de memoria es el
quebradero de cabeza mas comn
en miles de programadores en todo
el mundo.
Lenguaje C

USANDO VARIABLES
Cmo acceder a los elementos de
una variable?

Tanto el tipo de dato int como el nombre


de la variable edad no pueden ser
int accedidos de ninguna manera. Esto se
debe a que el Lenguaje C no soporta
caractersticas reflexivas que permitan
conocer detalles de las variables en
edad tiempo de ejecucin.

Esto nos da a entender que somos


responsables de conocer bien todas las
variables que utilizamos y de conocer sus
tipos de datos.

El resto de los elementos (tamao, valor y


direccin de memoria) si pueden ser
conocidos y accedidos en tiempo de
Lenguaje C

USANDO VARIABLES
Cmo saber el tamao de una
variable?

La funcin sizeof() nos permite calcular


el tamao en bytes de una determinada
int variable. El resultado debe ser
multiplicado por 8 si queremos conocer el
valor en bits
32 bits
edad

int edad;
sizeof(edad);
sizeof(unsigned int);
Tipos bsicos de datos

Las variables tipo char se usan para almacenar caracteres ASCII como A,1,&,
etc.
Cuando se desea trabajar con enteros, dependiendo del rango, se puede usar short, int
o long, con signo o sin signo.
Para trabajar con enteros sin signo, se debe anteponer la palabra reservada unsigned
delante del tipo (unsigned int). Esto nos permite aumentar el rango del tipo.
Por defecto son con signo, no hace falta anteponer la palabra signed.
Tipos de variables

longdouble 96 18 3.3621e-4932 1.18973e+493

Programacin en C 10
Lenguaje C

USANDO VARIABLES
Cmo ver o alterar el valor de una
variable?

Es broma !
Simplemente hacemos referencia a ella
int por su nombre en cualquier asignacin o
funcin

32 bits
edad
10
Lenguaje C

USANDO VARIABLES
Cmo saber la direccin de memoria
de una variable?

Para saber la direccin de memoria de


cualquier variable debemos usar el signo
int ampersand (&)

32 bits
edad
10
0x7fff2960d0ac

ATENCION !
Las direcciones de
memoria cambian con
cada ejecucin
ESPECIFICADORES DE FORMATO PARA SCANF
Y PRINTF
SECUENCIAS DE ESCAPE EN C
Cuando estamos escribiendo un programa puede que necesitemos representar la informacin de una forma
especial, con ciertas alineaciones, tabulaciones o estilos, en C es posible realizar estas tareas mediante las
llamadas secuencias de escape.
Lenguaje C

Los operadores & y *&

&
int

*
10 edad

& 0x7fff2960d0ac

Qu significan estos smbolos?

& = Referencia o Direccin de Memoria


*& = Dereferencia, Indireccin, Valor de direccin de memoria, Valor
Apuntado
Lenguaje C

Los operadores & y *&


int
&edad 0x7f5f0ac
10 edad
* &edad 10
0x7f5f0ac
* 0x7f5f0ac 10
USO DE LOS OPERADORES

Estos operadores se usan con cualquier objeto en memoria (variables,


estructuras, arrays, funciones, etc), sin embargo no pueden ser aplicadas
a expresiones, constantes o variables del tipo register

El operador & nos devolver la direccin de memoria. As de simple


Lenguaje C

Los operadores & y *&


int
&edad 0x7f5f0ac
10 edad
* &edad 10
0x7f5f0ac
* 0x7f5f0ac 10
USO DE LOS OPERADORES

El operador * tiene varios usos. Uno de ellos es la Indireccin el cual


permite acceder al valor guardado en una direccin de memoria.

Para efectuar una indireccin es indispensable que el operador * se


aplique a una direccin de memoria (por ejemplo *0x7f5f0ac)
Lenguaje C

Los operadores & y *&


DEMOSTRADO

La direccin de memoria se
puede obtener al usar el
operador & en cualquier
variable

El operador de indireccin
(*) es aplicado a
direcciones de memoria y
permite acceder al valor
almacenado en ella

Las direcciones de memoria


pueden utilizarse en su
Nota: Debido a que las direcciones memoria son asignadas en
tiempo de ejecucin, no es sencillo saber que direccin ocupara
forma hexadecimal
una determinada variable. Es por eso que se ha utilizado el
depurador gdb para hacer esta demostracin
Lenguaje C

Los operadores & y *&


* &eda
int
d
10 edad
* 0x7f5f0
ac
0x7f5f0ac

VALGAN VERDADES
1
0
A nadie en su sano juicio se le ocurrir utilizar una direccin de memoria
dentro del cdigo fuente. Ni que decir de la sentencia *&edad. Para que
alguien tendra que utilizar esta extraa sintaxis cuando simplemente
puede usar la variable con su simple nombre?.

edad = 10; // Este modo es el mas cuerdo CUAL


*&edad = 10; // A quien se le ocurrira usar esto por Dios !
USARIAS ?
Lenguaje C

QUE ES UN
PUNTERO
Recuerdan que nadie en su sano juicio usara la sentencia as:
*0x7f5f0ac?

Un puntero da solucin a ese problema !. Conocer las direcciones de


memoria brinda lo que hace al lenguaje C tan potente y requerido: Su
velocidad.

Un puntero es una variable especial capaz de guardar una direccin de


memoria de tal forma que no tenemos que recurrir a escribirlas dentro
del cdigo. Al poder guardar cualquier direccin de memoria, un puntero
puede tomarint*
posesin de cualquier variable deint
su tipo y literalmente
jugar con ella
0x7f5f0ac ptr 10 edad

0x503fb43 0x7f5f0ac
Lenguaje C

Punteros
Un puntero es un objeto que apunta a otro objeto. Es decir,
una variable cuyo valor es la direccin de memoria de otra
variable.
Las direcciones de memoria dependen de la arquitectura
del ordenador y de la gestin que el sistema operativo haga
de ella.

21
Lenguaje C

QUE ES UN
Examinando un Puntero
PUNTERO
Un puntero es una variable, y como tal,
int* tiene todos los elementos de cualquier
variable (tipo de dato, nombre, tamao
y direccin de memoria) . La nica
64 bits
diferencia visible es que al declararla,
ptr su tipo de dato debe ir acompaado del
0x7f5f0ac smbolo *

Debido a que debe contener


0x503fb43 direcciones de memoria, su tamao
debe ser lo suficientemente grande
para poder guardar cualquier direccin
de memoria del sistema operativo. Por
esta razn es muy comn que su
tamao sea de 64 bits (8 bytes) que
son suficientes para hacer referencia a
Lenguaje C

QUE ES UN
Declaracin de un puntero
PUNTERO
En mi humilde opinin, la confusin de
int* muchos programadores se debe a que
el smbolo * se usa para diferentes
cosas, entre ellas para declarar un
64 bits
puntero.
ptr
0x7f5f0ac int *ptr = &edad;
*ptr = 19;

0x503fb43 El cdigo anterior demuestra la


facilidad con la que puede confundir a
mas de un programador puesto que se
puede llegar errneamente a deducir
que el puntero ptr puede guardar
valores como el 19 y direcciones de
memoria como &edad. Lo cual es
Lenguaje C

QUE ES UN
Declaracin de un puntero
PUNTERO
A pesar que la gran mayora utiliza la
int* declaracin del modo int *ptr como la
normal, usar la siguiente declaracin
ayuda a evitar confundirla con la
64 bits
indireccin:
ptr
0x7f5f0ac int* ptr = &edad;
*ptr = 19;

0x503fb43 El cdigo anterior separa claramente lo


que es la variable puntero ptr y lo que
es la operacin de indireccin al
puntero ptr. Al parecer el estndar C99
se percato de esto y recomend crear
tipos de datos como intptr_t y
uintptr_t que no hacen mas que retirar
Lenguaje C

QUE ES UN
DEMOSTRADO
PUNTERO
Un puntero guarda direcciones de
memoria. As mismo un puntero al ser
una variable, tiene su propia direccin
de memoria

Con la indireccin no solo accedemos al


valor de la variable apuntada, sino que
tambin podemos modificar su valor.

Un puntero obtiene su valor a partir de


la referencia de una variable que se
consigue con el operador &

El tamao de un puntero puede ser


obtenido mediante la funcin sizeof()
Punteros
Los gestin de punteros admite dos
operadores bsicos:
Si px es un puntero (direccin): *px es el
contenido del puntero (el valor almacenado en la
direccin).

Si x es una variable: &x es la direccin de


memoria donde est almacenada la variable.

Programacin en C 26
Punteros
Direccin Contenido Grfica
int main() px
px-> 35: ? ? ? ? ?
0 0 0 3 y
{ y -> 39: 3

int *px,y=3;
px
px-> 35: 0 0 0 39 39
px=&y; y -> 39: 0 0 0 3 y
3
/* px apunta a y */
px
px-> 35: 0 0 0 39 39
*px=5; y -> 39: 0 0 0 5 y
5
/* y vale 5 */
}

Programacin en C 27
Punteros
La declaracin de punteros genricos a
direcciones se asocian al tipo void.
Declarar una variable (que no sea un puntero)
de tipo void no tiene sentido.
Ejemplo:
void *px,v; /* La variable v
est mal
declarada */

Programacin en C 28
Lenguaje C

PUNTERO
ENDEMONIADO
Por qu los punteros tienen fama
de ser complicados?
int*
La desventaja de los punteros es que
debemos ser muy disciplinados en su
uso y no es tarea fcil. Entre los errores
64 bits
mas comunes tenemos ptr
0x7f5f0ac
Punteros no inicializados
Asignacin de punteros errnea
Punteros con tipos distintos

0x503fb43
Indireccin errnea
Uso incorrecto de punteros nulos

Como podrs apreciar, son muchas


cosas las que pueden ir mal, es por eso
que los punteros requieren especial
Lenguaje C

PUNTERO
ENDEMONIADO
Punteros no inicializados

Todo puntero ANTES de ser utilizado


debe ser inicializado apropiadamente.
Es decir, su valor debe ser NULO o debe
contener la direccin de memoria de
una variable de su tipo de dato.

int edad = 10;


int* p;
*p = 19;

Si un puntero no esta inicializado y


hace uso de la operacin indireccin se
produce una Violacin de Segmento
y el programa terminar de forma
abrupta
Lenguaje C

PUNTERO
ENDEMONIADO
Violacin de Segmento

Lamentablemente cuando se declara


un puntero, toma como valor inicial una
direccin aleatoria usualmente fuera
del segmento de memoria del
programa.

La Violacin de Segmento se
produce porque un programa intenta
modificar o acceder a un segmento de
memoria que no le corresponde. El
Sistema Operativo al detectar esta
intrusin se protege y detiene el
programa agresor indicando que ha
violado un segmento que no le
corresponde.
Lenguaje C

PUNTERO
ENDEMONIADO
Inicializacin de puntero errnea

Otro error comn es olvidar colocar el


signo ampersand (&) al inicializar un
puntero.

Con ello se consigue que el puntero


guarde el valor de la variable y no su
direccin de memoria, la cual al ser
accedida provoca una violacin de
segmento

En el ejemplo que vemos,


errneamente le estamos indicando
que la direccin de memoria guardada
por ptr ser la posicin 0x10 (lo que
guarda la variable edad). Luego
Lenguaje C

PUNTERO
ENDEMONIADO
Punteros con tipos de datos
distintos

Los punteros deben ser declarados


segn el tipo de dato al que
apuntarn.

Si un puntero apunta a una variable


cuyo tipo de dato es distinto puede
convertirse en un problema si el
tamao del tipo de dato al que se
apunta es menor.

En el ejemplo podemos ver un


puntero de tipo int haciendo
referencia a la direccin de una
variable de tipo char. Esto conlleva a
Lenguaje C

PUNTERO
ENDEMONIADO
Indireccin errnea

Al ser la operacin mas comn de un


puntero, la indireccin ser errnea
siempre y cuando la declaracin o
incializacin este mal hecha

La indireccin en si misma no es un
error. El error viene al usarla en un
contexto errneo.

En el ejemplo podemos ver que la


indireccin no produce una violacin
de segmento, pero ha sido un error
alterar el valor mediante la
indireccin debido a que estamos
desbordando una variable de tipo
Lenguaje C

PUNTERO
ENDEMONIADO
Uso incorrecto de punteros nulos

El lenguaje C permite nulificar un


puntero para evitar acceder de forma
accidental a otra direccin de
memoria fuera de nuestro segmento
permitido.

Sin embargo, veamos que pasa


cuando no utilizamos adecuadamente
los punteros nulos

En el ejemplo podemos ver que a


pesar de poner un puntero a NULL
podemos causar problemas si
realizamos una indireccin. Esto
naturalmente tiene sentido debido a
Lenguaje C

TIPOS DE DATOS BASICOS PARA


PUNTEROS
Y a que tipos de datos puedo
char* apuntar?

En realidad, podemos apuntar a


int* cualquier tipo de dato que usemos
en el Lenguaje C

float* Los tipos de datos comunes suelen


ser los tipos de datos bsicos a los
double* cuales un puntero podr hacer
referencia.

void* Incluso podemos usar el puntero


void* que nos permite apuntar a
cualquier tipo de dato. El resto de
punteros solo puede apuntar a su
Lenguaje C

ASIGNACION DE
PUNTEROS
La clave en el uso de todo puntero es
su correcta asignacin (inicializacin).
int*
La asignacin de punteros es una
operacin que permite indicar que
direccin de memoria tomar un
64 bits
puntero determinado. ptr
0x7f5f0ac
Hay 2 tipos de asignacin de punteros

Asignacin de variable a puntero


Asignacin de puntero a puntero
0x503fb43

La primera es la habitual, que permite


apuntar a una variable determinada.
Lenguaje C

ASIGNACION DE
PUNTEROS
Asignacin de variable a puntero

Para asignar una variable a un puntero int*


podemos usar la declaracin del
puntero
64 bits
int edad = 10; ptr
int* ptr = &edad;
0x7f5f0ac
Sin embargo, tambin podemos usar
esta forma
0x503fb43
int edad = 10;
int* ptr;
ptr = &edad;

La 2da forma no se recomienda por ser


Lenguaje C

ASIGNACION DE
PUNTEROS
Asignacin de puntero a puntero

Una caracterstica muy til es que los


punteros pueden compartir sus datos
entre si. Es decir, mas de un puntero
puede apuntar a la misma variable

int edad = 10;


int* ptr1 = &edad;
int* ptr2 = ptr1; // No requiere &
*ptr2 = 19;

La ventaja es que lo que cambia un


puntero se ve reflejado en el otro. Solo
debemos tener en cuenta que al
asignar un puntero a otro, NO ES
NECESARIO usar el signo &
OPERACIONES CON LOS PUNTEROS

Sobre una variable puntero se pueden realizar una serie de operaciones


que veremos a continuacin:
Direccin: el operador de direccin no es realmente uno que se aplique
sobre las variables puntero (normalmente), sino sobre otros tipos de
variable. ste operador, representado con el smbolo ampersand (&)
obtiene la direccin de memoria de la variable a la que precede. As, si la
variable entera w est almacenada en la posicin de memoria 32012, la
operacin int *punt; punt= &w; asignar el valor 32012 a la variable punt.
Indireccin: el operador de desreferenciacin o de indireccin s se
aplica a valores de tipo puntero. ste operador se representa por un
asterisco (*) y devuelve un valor del tipo apuntado por el operando. Este
valor es el contenido en la posicin apuntada por el puntero. As, en el
siguiente cdigo
float *p; float q= 1.44;
p= &q; print("%f\n",
el valor *p); es 1.44, ya que p apunta a la direccin de q. En
que se imprime
general, si el puntero x apunta a un tipo de datos T, la expresin *x es de
tipo T.
OPERACIONES CON LOS PUNTEROS
Asignacin de punteros: Es posible asignar una direccin de una variable
a un puntero (ej1) Es posible asignar el contenido de un puntero a otro
puntero (ej2)
OPERACIONES CON LOS PUNTEROS

Aritmtica de punteros: Se trata de sumar y restar, incrementar


o decrementar variables de tipo puntero Debe entenderse
como cambios en la direccin a la que apunta el puntero (se
produce un cambio en la direccin de memoria contenida en el
puntero). El incremento o decremento de un puntero depende
exclusivamente del tipo de dato base dado en la declaracin
del puntero. Al declarar un puntero es necesario indicar a qu
tipo de dato apunta para que cuando se utilicen los
incrementos o decrementos se conozca cunto hay que sumar
o restar. La operacin de sumar 1 a un puntero hace que su
direccin se incremente la cantidad necesaria para pasar a
apuntar al siguiente dato del mismo tipo (cantidad que coincide
con el nmero de bytes que ocupa dicho tipo de dato). Por lo
tanto, slo en el caso de variables que ocupan 1 byte en
memoria (variables de tipo char) la operacin de incremento
aumenta en 1 la direccin de memoria; en los dems casos
aumenta ms.
OPERACIONES CON LOS
PUNTEROS
Incremento, decremento: los valores de tipo puntero se pueden
incrementar y decrementar, siempre en valores enteros. Se admiten los
operadores + , , ++ y .
OPERACIONES CON LOS PUNTEROS
OPERACIONES CON LOS PUNTEROS
Arrays y punteros
El identificador de una variable array tiene el
valor de la direccin de comienzo del mismo.
Por lo tanto, su valor puede usarse como un
puntero.
a 1020304050
int *pb,*pc;
pb pc
int a[5]={10,20,30,40,50}; a 1120304050
pb=a; pb pc

*pb=11; a 1120304450
pc=&a[3]; pb pc

*pc=44;

Programacin en C 48
RECORRIDO DE UN VECTOR UTILIZANDO
NDICES Y PUNTEROS

#include <stdio.h>
main()
{
int v[10];
int i, *p;
for (i=0; i < 10; i++) v[i] = i;
for (i=0; i < 10; i++) printf ("\n%d", v[i]);
p = v;
for (i=0; i < 10; i++) printf ("\n%d", *p++);
/* Tras cada p++ el puntero seala a la siguiente posicin en v
*/
return 0;
}
Punteros y vectores
Una de las aplicaciones ms frecuentes de los punteros es el
manejo de vectores y cadenas de caracteres.
Como todos los elementos de un vector se almacenan en posiciones
consecutivas de memoria, basta conocer la posicin de memoria del
primer elemento para poder recorrer todo el vector con un puntero.

S-ar putea să vă placă și