Programación No Numérica: Los Apuntadores
Este Blog fue realizado por el Bachiller Franco Marrocco para la materia Programación No Numérica, sección V del Instituto Universitario Politécnico Santiago Mariño. Se explicará como tema principal todo lo referente a Apuntadores.
sábado, 8 de julio de 2017
Inicialización De Apuntadores
< Almacenamiento > < Tipo > * < Nombre
> = < Expresión >
Si <Almacenamiento> es extern o static,
<Expresión> deberá ser una expresión constante del tipo <Tipo>
expresado.
Si <Almacenamiento> es auto, entonces
<Expresión> puede ser cualquier expresión del <Tipo> especificado.
Ejemplos:
1. La constante entera 0, NULL (cero) proporciona un
apuntador nulo a cualquier tipo de dato:
int *p;
p = NULL; //actualización
2. El nombre de un arreglo de almacenamiento static o extern se
transforma según la expresión:
a.
float mat[12];
float
*punt = mat;
b.
float mat[12];
float
*punt = &mat[0];
3. Un “cast” apuntador a apuntador:
int *punt = (int *) 123.456;
Inicializa el apuntador con el entero. Esto
es, en la dirección a la que apunta la variable punt se almacena el valor 123.
4. Un apuntador a carácter puede inicializarse en la forma:
char *cadena = Esto es una cadena”;
5. Se pueden sumar o restar valores enteros a las
direcciones de memoria en la forma:
(aritmética de apuntadores)
static int x;
int
*punt = &x+2, *p = &x-1;
6. Equivalencia: Dos tipos definidos como apuntadores a objeto P y apuntador a objeto son equivalentes
sólo si P y Q son del mismo tipo. Aplicado a
matrices:
nombre_apuntador = nombre_matriz;
Declaración e inicialización de apuntadores
Aritmética De Apuntadores
La aritmética de punteros se limita a suma,
resta, comparación y asignación. Las operaciones aritméticas en los punteros de
tipoX (punteros-a-tipoX) tienen automáticamente en cuenta el tamaño real de
tipoX. Es decir, el número de bytes necesario para almacenar un objeto tipoX
[2]. Por ejemplo, suponiendo una matriz de double con 100 elementos, si ptr es
un puntero a dicha matriz, la sentencia ptr++; supone incrementar el Rvalue de
ptr en 6.400 bits, porque el tamaño de la matriz es precisamente 100x64 bits.
Nota:
no confundir el puntero-a-matriz con un puntero a su primer elemento (que aquí
sería puntero-a-double).
La aritmética realizada internamente en los
punteros depende del modelo de memoria en uso y de la presencia de cualquier
modificador superpuesto.
Las operaciones que implican dos punteros
exigen que sean del mismo tipo o se realice previamente un modelado
apropiado .
Sean ptr1, ptr2 punteros a
objetos del mismo tipo, y n un tipo entero o una enumeración; las
operaciones permitidas y los resultados obtenidos con ellas son:
La comparación de punteros solo tiene sentido
entre punteros a elementos de la misma matriz; en estas condiciones los
operadores relacionales ( 4.9.12): ==,
!=, <, >, <=, >=,
funcionan correctamente.
Cuando se crea un arreglo unidimensional o de
'n' dimensiones, todos los elementos de dicho arreglo se acomodan en la memoria
de manera adjunta o lineal, es decir, se puede desplazar por el arreglo
moviéndonos de una dirección de memoria a otra con un apuntador, y simplemente
sumando o restando unidades al apuntador se logra que dicho apuntador pueda
recorrer el arreglo.
En la siguiente imagen se puede ver como se
almacena un arreglo y como apuntar a él:
Como se puede observar todos los elementos del
arreglo están adjuntos entre ellos, si el arreglo fuera bi-dimensional sería lo
mismo.
Asignación De Apuntadores
Se pueden asignar a un apuntador direcciones de
variables a través del operador de referenciación (‘&’) o direcciones
almacenadas en otros apuntadores.
Ejemplos:
Ejemplos:
Un apuntador puede convertirse en un alias de
una variable destino (target) a través de una sentencia de asignación de
punteros, que es ejecutable y tiene la forma:
Donde puntero es una
variable con atributo pointer y objetivo es una
variable con atributo target o bien atributo pointer. Una vez
que un puntero se convierte en alias de un destino, se puede utilizar en
cualquier punto en lugar de la variable destino.
La figura muestra algunos ejemplos de
asignaciones con punteros. Téngase en cuenta que una asignación como:
p2 => p1 + 4.3 ! Error
No está permitida porque no se puede asociar un puntero
con una expresión aritmética.
El destino de un puntero puede ser también un vector. La
figura muestra algunos ejemplos de esta posibilidad. Hay varios aspectos que
hemos de tener en cuenta:
El puntero pv1 se asocia en diferentes momentos con
vectores (secciones de vector) de diferentes extensiones. Esto se permite
porque lo que cuenta es el rango, no la extensión.
Declaración De Apuntadores.
Cuando se declara una variable, el compilador
reserva un espacio de memoria para ella y asocia el nombre de ésta a la
dirección de memoria desde donde comienzan los datos de esa variable. Las
direcciones de memoria se suelen describir como números en hexadecimal. Un
apuntador es una variable cuyo valor es la dirección de memoria de otra
variable. Se dice que un apuntador “apunta” a la variable cuyo valor se
almacena a partir de la dirección de memoria que contiene el apuntador. Por
ejemplo, si un apuntador p almacena la dirección de una variable x, se dice que
“p apunta a x”.
Los apuntadores como cualquier otra variable
deben de ser declarados antes de que puedan ser utilizados. El tipo de un
apuntador lo proporciona implícitamente el tipo de la variable a la que apunta.
Los apuntadores pueden ser declarados para
apuntar a objetos de cualquier clase.
La sintaxis general de declaración es:
<tipo> *
<variable>
Ejemplos de declaraciones:
La variable contPtr es del tipo apuntador a
entero, (int *) y se lee ``contPtr es un apuntador a int'' o ``contPtr apunta a
una variable entera''.
NOTA: Un apuntador a cualquier tipo de variables es una
dirección en memoria, la cual es una dirección entera, pero un apuntador NO es
un entero.
La razón por la cual se asocia un apuntador a un tipo de
dato, es por que se debe conocer en cuantos bytes esta guardado el dato. De tal
forma, que cuando se incrementa un apuntador, se incrementa el apuntador por un
``bloque'' de memoria, en donde el bloque esta en función del tamaño del dato.
Por lo tanto para un apuntador a un char, se agrega un byt a la dirección y
para un apuntador a entero o a flotante se agregan 4 bytes. De esta forma si a
un apuntador a flotante se le suman 2, el apuntador entonces se mueve dos
posiciones float que equivalen a 8 bytes.
Para
declarar un apuntador se especifica el tipo de dato al que apunta, el operador
‘*’, y el nombre del apuntador. La sintaxis es la siguiente:
<tipo de dato apuntado> *<indentificador del
apuntador>
A continuación se muestran varios ejemplos:
Ejemplos
En los ejemplos siguientes se muestran
declaraciones de puntero.
char *message; /* Declares a pointer variable named message */
El puntero message señala a una
variable con el tipo char.
int *pointers[10]; /* Declares an
array of pointers */
La matriz de pointers tiene 10
elementos; cada elemento es un puntero a una variable con el tipo int.
int (*pointer)[10]; /* Declares a pointer to an array of 10 elements */
La variable de puntero señala a una matriz
con 10 elementos. Cada elemento de esta matriz tiene el tipo int.
int const *x; /* Declares a
pointer variable, x,
to a constant value */
El puntero x se puede modificar
para que señale a un valor int diferente, pero el valor al que señala
no puede modificarse.
const
int some_object = 5 ;
int
other_object = 37;
int
*const y = &fixed_object;
int
volatile *const z = &some_object;
int
*const volatile w = &some_object;
La variable y en estas
declaraciones se declara como un puntero de constante a un valor int. El
valor al que señala se puede modificar, pero el propio puntero debe señalar
siempre a la misma ubicación: la dirección de fixed_object. De igual
forma, z es un puntero de constante, pero también se declara para que
señale a un elemento int cuyo valor no lo pueda modificar el
programa.
El especificador
adicional volatile indica que aunque el valor de const int al que
señala z no lo puede modificar el programa, podría modificarlo de
forma legítima un proceso ejecutado simultáneamente con el programa. La
declaración de w especifica que el programa no puede cambiar el valor
al que se señala y que el programa no puede modificar el puntero.
struct list *next, *previous; /* Uses the tag for list */
En este ejemplo se declaran dos variables de
puntero, next y previous, que señalan al tipo de
estructura list. Esta declaración puede aparecer antes que la definición
del tipo de estructura list (vea el ejemplo siguiente), mientras que
la definición de tipo list tiene la misma visibilidad que la
declaración.
struct
list
{
char *token;
int count;
struct list *next;
} line;
La variable line tiene el tipo de
estructura denominado list. El tipo de estructura list tiene
tres miembros: el primer miembro es un puntero a un valor char, el segundo
es un valor int y el tercero es un puntero a otra
estructura list.
struct
id
{
unsigned int id_no;
struct name *pname;
} record;
La variable record tiene el tipo de
estructura id. Observe que pname se declara como un puntero a
otro tipo de estructura denominado name. Esta declaración puede aparecer
antes de que se defina el tipo name.
Operaciones De Apuntadores
1. Un operador de dirección &:
Representa
la dirección de memoria de la variable que le sigue; Operador unario que regresa
la dirección de su operando, ejemplo:
main()
{
int
y;
int
*yPtr;
y =
5;
yPtr = &y;
}
2. Un operador de indirección o de desreferencia:
*. El operador * aplicado al nombre de un apuntador indica
el valor de la variable apuntada; Regresa el valor del objeto hacia el cual su
operando apunta, es decir un apuntador, ejemplo:
main()
{
int x,y;
int *py;
int x,y;
int *py;
y = 5;
*py = y;
x = *py + 5;
printf(''%d %d nn'',*py,x);
}
*py = y;
x = *py + 5;
printf(''%d %d nn'',*py,x);
}
Se verá con un ejemplo en C la diferencia entre todos estos conceptos
Es
decir: int x = 25, *pint;
pint
= &x;
La variable pint contiene la dirección
de memoria de la variable x. La expresión: *pint representa el valor de la
variable (x) apuntada, es decir 25. La variable pint también
tiene su propia dirección: &pint
• Se pueden realizar asignaciones entre punteros.
int
a = 15;
int
*p, *q;
q =
&a;
p = q; /*
se asigna la dirección que contiene q a p */
cout<<p; /* imprime la dirección almacenad en p. */
• Se pueden operar solamente el +, el -, el ++ y el --.
Int p;
p = p + 1; p
avanza un entero.
p = p – 2; p
retrocede dos enteros.
p++; p
apunta al siguiente entero.
p--; p
apunta al entero anterior.
• Los punteros se pueden comparar.
int 2;
En el siguiente código se realiza un programa que emplea
los operadores (& y *).
#include
<iostream.h>
#include
<conio.h>
int main()
{
clrscr();
int a;
//a es un puntero
int * ap; //ap
es un apuntador a un puntero
a = 7;
ap=
& a; //ap toma la dirección de
a
cout
<<"la dirección de a es " <<&a;
cout<<" \n el Valor de ap es "
<< ap;
cout
<<"\n el valor de a es" <<a;
cout<<"\n el valor de *ap es "
<< *ap;
cout<<"\n\n\n Mostrando los valores
de * y &" ;
cout <<"\n
&* ap = " <<&*ap;
cout <<"\n *& ap = "
<< *≈
getch();
return
0;
}
Los Apuntadores
Cuando se declara una variable, el compilador
reserva un espacio de memoria para ella y asocia el nombre de ´está a la
dirección de memoria desde donde comienzan los datos de esa variable. Las
direcciones de memoria se suelen describir como números en hexadecimal.
Un apuntador es una variable cuyo valor es la
dirección de memoria de otra variable. Se dice que un apuntador “apunta” a la
variable cuyo valor se almacena a partir de la dirección de memoria que
contiene el apuntador. Por ejemplo, si un apuntador p almacena la dirección de
una variable x, se dice que “p apunta a x”.
Los apuntadores son variables que almacenan
direcciones de memoria.
· En general una
variable contiene un valor específico dependiendo de cómo fue declarada.
· Un apuntador contiene
la dirección de una variable que contiene un valor específico.
· Una variable se
refiere directamente a un valor y un apuntador se refiere indirectamente a un
valor.
· Apuntadores usados en
C debido a que a veces son la única manera de expresar un cálculo.
· Se puede llegar a
obtener un código más compacto y eficiente.
· Cuando se emplean sin
cuidado pueden crear programas imposibles de entender.
· Cuentan con una
declaración propia.
· Los apuntadores
disponen de dos operadores:
· El operador unario o monádico “&”
devuelve la dirección de memoria de una variable;
· El operador de indirección o desreferencia “*”
devuelve el "contenido de un objeto apuntado por un apuntador''.
Hay que recordar que:
·
Una variable es un campo de memoria destinado
a almacenar datos que
pertenezcan a un determinado tipo
de dato.
·
Todo campo de memoria es un segmento
de RAM que se reconoce
por la asignación de una dirección representada
en hexadecimal.
Un apuntador es…
- Una variable que puede almacenar específicamente direcciones de memoria.
- Variable cuyo dato es la dirección de memoria de otra variable.
![]() |
Suscribirse a:
Entradas (Atom)