Está en la página 1de 26

Puntero (informática)

En ciencias de la computación, un puntero es un objeto del lenguaje


de programación, cuyo valor se refiere a (o "apunta a") otro valor Considero que las sentencias
almacenado en otra parte de la memoria del ordenador utilizando su de asignación y variables
puntero están entre los
dirección. Un puntero referencia a una ubicación en memoria, y a la tesoros más valiosos de la
obtención del valor almacenado en esa ubicación se la conoce como informática
desreferenciación del puntero. A modo de analogía, un número de —Donald Knuth, Structured
página en el índice de un libro podría considerarse un puntero a la Programming with go to
página correspondiente; desreferenciar un puntero sería como ir a la Statements1
página con el número de página especificada en el índice.

Los punteros a datos mejoran significativamente el rendimiento de


las operaciones repetitivas tales como cadenas de desplazamiento,
tablas de búsqueda, tablas de control y estructuras árbol. En
particular, muchas veces es mucho más barato en tiempo y espacio
copiar y des referenciar punteros que copiar y acceder a los datos a
los cuales apunta el puntero.

Los punteros también se utilizan para mantener las direcciones de


los puntos de entrada para las subrutinas para llamadas en
programación por procedimientos y enlaces para vincular a las
bibliotecas de enlace dinámico (DLL) en tiempo de ejecución. En
la programación orientada a objetos, los punteros a funciones se
utilizan para métodos de unión, muchas veces utilizando lo que se
llama tablas de métodos virtuales.
Puntero 'a' apuntando a la dirección
Un puntero es una implementación más concreta y simple del tipo de memoria asociada con la variable
'b'. Obsérvese que en este diagrama
de datos de referencia más abstracto. Varios lenguajes soportan
en particular, la arquitectura de
algún tipo de puntero, aunque algunos tengan más restricciones en
cálculo utiliza el mismo espacio de
su uso que otros. Mientras que se utilice un "puntero" para referirse
direcciones y datos primitivos tanto
a referencias en general, se aplica más propiamente a las estructuras
para punteros como para no
de datos cuya interfaz permita explícitamente que el puntero sea
punteros; esto no tiene por qué ser el
manipulado (aritméticamente vía aritmética de punteros) como una
caso.
dirección de memoria, en oposición a una cookie u opción dónde
esto no sea posible.[cita  requerida] Debido a que los punteros
permiten tanto proteger como permitir el acceso a direcciones de memoria, hay riesgos asociados con su
uso, sobre todo en este último caso. Generalmente, los punteros primitivos son almacenados en un formato
similar a un entero; no obstante, intentar eliminar la referencia o "mirar hacia arriba" hacia un puntero cuyo
valor no fue nunca una dirección de memoria válida conllevaría a provocar que un programa se bloquee.
Para aliviar este potencial problema, como una cuestión de seguridad de tipos, los punteros son
considerados un tipo separado parametrizado por un tipo de datos que apuntan a, incluso si la
representación subyacente es un número entero. También se pueden tomar otras medidas (como la
validación y comprobación de los límites, para verificar el contenido de la variable de puntero contenga un
valor que es a la vez una dirección de memoria válida y dentro del rango numérico que el procesador sea
capaz de abordar).
Índice
Historia
Descripción formal
Usos en estructuras de datos
Uso en tablas de control
Orígenes en la arquitectura de ordenador
Usos
Punteros en C
Matrices de C
Lista vinculada en C
Pasaje por dirección utilizando punteros
Asignación dinámica de memoria
Hardware asignado en memoria
Punteros con tipo y fundición
Haciendo más seguros a los punteros
Puntero nulo
Puntero auto relativo
Puntero base
Indirección múltiple
Puntero a función
Puntero salvaje
Simulación utilizando un índice de matriz
Punteros en lenguajes de programación
Estructuras
Uniones
Matrices
Soporte en lenguajes de programación
Ada
BASIC
C y C++
C#
COBOL
PL/I
D
Eiffel
Fortran
Go
Java
Modula-2
Oberon
Pascal
Pauscal
Perl
Véase también
Referencias
Enlaces externos

Historia
Se le atribuye a Harold Lawson la invención del puntero en 1964.2 ​ En 2000, Lawson fue presentado el
Premio Pionero de Informática por la IEEE "[por la invención de la variable puntero y la introducción de
este concepto en PL /I, proporcionando así, por primera vez, la capacidad de tratar con flexibilidad las listas
enlazadas en un lenguaje de alto nivel de propósito general".3 ​ Según el Diccionario inglés de Oxford, la
palabra puntero apareció impresa por primera vez como un puntero de pila en un memorando técnico de la
System Development Corporation (Corporación de Desarrollo de Sistemas).

Descripción formal
En ciencias de la computación, un puntero es un tipo de referencia.

Un dato primitivo (o simplemente primitivo) es cualquier dato que puede ser leído o escrito en la memoria
del ordenador usando un acceso de memoria (por ejemplo, tanto un byte como una palabra son primitivas).

Un agregado de datos (o simplemente agregado) es un grupo de primitivos que son lógicamente contiguos
en la memoria y que son vistos colectivamente como un dato (por ejemplo, un agregado podría ser 3 bytes
lógicamente contiguos, los valores de los cuales representan las 3 coordenadas de un punto en el espacio).
Cuando un agregado está compuesto enteramente del mismo tipo de primitiva, dicho agregado puede
denominar matriz; en cierto sentido, una palabra multi-byte primitiva es una matriz de bytes, y algunos
programas de usan palabras de esta manera.

Un puntero de memoria (o simplemente puntero) es un valor primitivo del cual está destinado a ser
utilizado como una dirección de memoria; se dice que un puntero apunta a una dirección de memoria.
También se dice que un puntero apunta a un dato [en memoria] cuando el valor del puntero es la dirección
de memoria de referencia.

Más en general, un puntero es un tipo de referencia, y se dice que un puntero referencia a un dato
almacenado en algún lugar de la memoria; para obtener ese dato se desreferencia el puntero. La
característica que separa punteros de otros tipos de referencia es que el valor de un puntero está destinado a
ser interpretado como una dirección de memoria, que es un concepto bastante de bajo nivel.

Las referencias sirven como un nivel de indirección: El valor de un puntero determina que la dirección de
memoria (es decir, cual dato) está siendo utilizado en un cálculo. Debido a que la indirección es un aspecto
fundamental de los algoritmos, generalmente los punteros son expresados como un tipo de datos
fundamental en lenguajes de programación; en forma de lenguajes de programación estáticos (o
fuertemente) tipados, el tipo de un puntero determina el tipo de dato al que apunta el puntero.

Usos en estructuras de datos


Cuando se configuren estructuras de datos como listas, colas y árboles, es necesario contar con indicadores
para ayudar a controlar cómo se implementa y controla la estructura. Ejemplos típicos de punteros son los
de inicio, los punteros finales y los punteros de pila. Estos indicadores pueden ser o bien absolutos
(dirección física real o una dirección virtual en la memoria virtual) o relativos (un desplazamiento desde
una dirección inicial absoluta ("base") que suele utilizar menos bits que una dirección completa, pero por lo
general requieren una operación aritmética adicional para resolverse).

Las direcciones relativas son una forma de segmentación de memoria manual, y comparten muchas de sus
ventajas y desventajas. Una compensación de dos bytes, que contiene un entero sin signo de 16 bits, se
puede utilizar para proporcionar direccionamiento relativo de hasta 64 kilobytes de una estructura de datos.
Esto se puede extender fácilmente a 128K, 256K o 512K si la dirección apuntada se ve obligada a alinearse
- a mitad de palabras, palabra o doble palabra (pero, lo que requiere una operación de "desviación a la
izquierda" a nivel de bits para 1, 2 o 3 bits-con el fin de ajustar el desplazamiento por un factor de 2, 4 u 8,
antes de su adición a la dirección de base). Sin embargo, por lo general esos planos tienen un montón de
problemas, y por conveniencia para el programador son preferibles las direcciones absolutas del
programador (y subyacente a esa, un espacio de dirección plano).

Un desplazamiento de un byte, tal como el valor ASCII hexadecimal de un carácter (por ejemplo, X'29') se
puede utilizar para apuntar a un valor alternativo entero (o índice) en una matriz (por ejemplo, X'01'). De
esta manera, los caracteres pueden ser traducidos de manera muy eficiente partiendo de datos brutos, a un
índice secuencial utilizable y luego a una dirección absoluta sin utilizar una tabla de búsqueda.

Uso en tablas de control


Por lo general, las tablas de control, que se utilizan para controlar el flujo del programa hacen un amplio
uso de punteros. Los punteros, normalmente integrados en una entrada de la tabla, pueden, por ejemplo, ser
usados para sostener los puntos de entrada a subrutinas a ser ejecutados, basado en ciertas condiciones
definidas en la misma entrada de la tabla. Sin embargo, los indicadores pueden ser simples índices de otros
cuadros distintos, pero relacionados, que comprenden un conjunto de las direcciones reales o direcciones
propias (dependiendo de las construcciones disponibles del lenguaje de programación). También pueden
utilizarse para señalar (retrocediendo) a entradas de la tabla anterior (como en el procesamiento de bucle) o
avanzar para pasar algunas entradas de la tabla (como en un switch o salida "prematura" de un bucle). A
este último efecto, el "puntero" simplemente puede ser el número de entrada de la tabla en sí y puede pasar
a ser una dirección actual usando aritmética simple.

Orígenes en la arquitectura de ordenador


Los punteros son una abstracción muy delgada en la parte superior de las capacidades de direccionamiento
ofrecidas por la mayoría de las arquitecturas modernas. En el esquema más simple, una dirección, o un
índice numérico, se asigna a cada unidad de memoria en el sistema, donde la unidad es típicamente un byte
o una palabra - dependiendo de si la arquitectura es direccionable por byte o direccionable por palabra -
transformando eficazmente toda la memoria en una matriz muy grande. Entonces, si tenemos una dirección,
el sistema provee una operación para recuperar el valor almacenado en la unidad de memoria en esa
dirección (por lo general la utilización de registros de propósito general de la máquina).

En el caso usual, un puntero es lo suficientemente grande como para contener más direcciones que no sean
unidades de memoria en el sistema. Esto introduce la posibilidad de que un programa puede intentar
acceder a una dirección que corresponde a ninguna unidad de memoria, ya sea porque no hay suficiente
memoria instalada (es decir, más allá del rango de memoria disponible) o porque la arquitectura no soporta
dichas direcciones. En el primer caso, en ciertas plataformas como la arquitectura x86 de Intel, se llama un
fallo de segmentación (violación de segmento). El segundo caso es posible en la actual aplicación de
AMD64, donde los punteros son de 64 bits de largo y direcciones solo se extienden a 48 bits. Allí, punteros
deben ajustarse a ciertas normas canónicas (direcciones), así que si un puntero no canónica se eliminan las
referencias, el procesador plantea un error de protección general.

Por otra parte, algunos sistemas tienen más unidades de memoria que no son direcciones. En este caso, se
emplea un esquema más complejo, tal como la segmentación de memoria o de paginación a utilizar
diferentes partes de la memoria en diferentes momentos. Las últimas encarnaciones de la arquitectura x86
soportan hasta 36 bits de direcciones de memoria física, que fueron asignadas al espacio de direcciones
lineal de 32 bits usando un mecanismo PAE de paginación. Así, solo el 1/16 de la posible memoria total
puede ser accedida a la vez. Otro ejemplo de la misma familia de ordenadores estaba el modo protegido de
16 bits del procesador 80286, que, sin embargo, soportaba solamente 16 MiB de memoria física, pudiendo
acceso a un máximo de 1 GiB de memoria virtual, pero la combinación de dirección de 16 bits y el
segmento de registros hizo acceder a más de 64 KiB en una estructura de datos engorroso. Algunas
restricciones de la aritmética del puntero ANSI pudieron haberse debido a los modelos de memoria
segmentadas de esta familia de procesadores. [cita requerida]

Con el fin de proporcionar una interfaz consistente, algunas arquitecturas proporcionan E/S mapeada en
memoria, lo que permite a algunas direcciones que se refieren a las unidades de memoria, mientras que
otros se refieren a los registros de dispositivos de otros dispositivos en el ordenador. Hay conceptos
análogos tales como desplazamientos de archivo, los índices de matriz, y las referencias a objetos remotos
que sirven algunos de los mismos propósitos que las direcciones de otros tipos de objetos.

Usos
Los punteros son compatibles directamente sin restricciones en lenguajes como PL/1, C, C++, Pascal, y la
mayoría de los lenguajes ensambladores. Se utilizan principalmente para la construcción de referencias, que
a su vez son fundamentales para la construcción de casi todas las estructuras de datos, así como para pasar
datos entre las diversas partes de un programa.

En los lenguajes de programación funcionales que dependen en gran medida de las listas, los punteros y
referencias son gestionados de manera abstracta por el lenguaje utilizando construcciones internas como
const.

Cuando se trata de matrices, la crítica operación de búsqueda suele implicar un cálculo de dirección etapa
llamada que implica la construcción de un puntero al elemento de datos deseado en la matriz. Si los
elementos de datos en la matriz tienen longitudes que son divisibles por potencias de dos, esta aritmética es
por lo general un poco más eficiente.[cita requerida] El relleno generalmente es usado como un mecanismo
para asegurar que este sea el caso, a pesar del aumento de los requerimientos de memoria. En otras
estructuras de datos, tales como las listas enlazadas, los punteros se utilizan como referencias para vincular
de forma explícita una sola pieza de la estructura a otra.

Los punteros se utilizan para pasar parámetros por referencia. Esto es útil si el programador quiere
modificaciones de una función a un parámetro sea visible para llamador de la función de la función. Esto
también es útil para devolver varios valores de una función.

Los punteros también se puede utilizar para asignar y desasignar en la memoria variables dinámicas y
matrices. Ya que muchas veces una variable puede volverse redundante después de que haya cumplido su
objetivo, que resulta en una pérdida de la memoria mantenerla, en consecuencia es una buena práctica para
desasignarla cuando ya no se necesita, utilizando la referencia de puntero original. El no hacerlo puede
resultar en una pérdida de memoria (donde la memoria libre disponible va disminuyendo gradualmente, o
en casos severos rápidamente, a causa de una acumulación de numerosos bloques de memoria
redundantes).
Punteros en C

La sintaxis básica para definir un puntero es:4 ​

int * ptr;

Esto declara ptr como el identificador de un objeto, de la siguiente forma:

puntero que apunta a un objeto de tipo int

Esto usualmente se manifiesta de forma más sucinta como 'ptr es un puntero a int.'

Debido a que el lenguaje C no especifica una inicialización implícita para los objetos de duración
automática de almacenamiento,5 ​ frecuentemente se debe prestar atención para asegurarse de que la
dirección a la que ptr puntea es válida; por eso a veces se sugiere que un puntero pueda ser
explícitamente inicializado al valor de puntero nulo, que es tradicionalmente especificado en C con la
macro estandarizado NULL:6 ​

int *ptr = NULL;

Desreferenciar un puntero nulo en C produce un comportamiento indefinido,7 ​ que podría ser catastrófico.
Sin embargo, la mayoría de las implementaciones [cita  requerida], simplemente detienen la ejecución del
programa en cuestión, usualmente con un fallo de segmentación.

Sin embargo, punteros inicializados podría obstaculizar innecesariamente el análisis del programa,
ocultando de ese modo los bugs.

En cualquier caso, una vez que un puntero ha sido declarado, el siguiente paso lógico es que se apunte a
algo:

int a = 5;

int *ptr = NULL;

ptr = &a;

Esto asigna el valor de la dirección de a a ptr. Por ejemplo, si a está almacenado en la ubicación de
memoria de 0x8130 entonces el valor de ptr será 0x8130 después de la asignación. Para eliminar la
referencia al puntero, se utiliza de nuevo el asterisco:

*ptr = 8;

Esto significa tomar el contenido de ptr (que es 0x8130), "localizar" la dirección en memoria y establecer
su valor en 8. Si, más tarde, se accede de nuevo, su nuevo valor será 8.

Este ejemplo puede ser más claro si la memoria no es directamente examinada.


Supongamos que a se
localiza en la dirección 0x8130 en memoria y ptr en 0x8134; también asume de que se trata de un equipo
de 32 bits de tal manera que un int tiene un ancho de 32 bits. Lo que sigue es lo que estaría en la
memoria después de que se ejecuta el siguiente fragmento de código:
int a = 5;

int *ptr = NULL;

Dirección Contenido
0x8130 0x00000005
0x8134 0x00000000

(El puntero NULL que se muestra aquí es 0x00000000.)


Mediante la asignación la direcciona de a a ptr:

ptr = &a;

produce los siguientes valores de memoria:

Dirección Contenido
0x8130 0x00000005
0x8134 0x00008130

Entonces desreferenciando ptr mediante codificación:

*ptr = 8;

la computadora tendrá el contenido de ptr (que es 0x8130), 'localizado' esa dirección, y asignar 8 a esa
ubicación produciendo la siguiente memoria:

Dirección Contenido
0x8130 0x00000008
0x8134 0x00008130

Claramente, el acceso a a producirá el valor de 8 porque la instrucción anterior modificó el contenido de a


por medio del puntero ptr.

Matrices de C

En C, la indización de matrices se define formalmente en términos de punteros aritméticos, es decir, la


especificación del lenguaje requiere que array[i] sea equivalente a *(array + i).8 ​Así, en C, las
matrices pueden ser consideradas como punteros a áreas de memoria consecutivas (sin espacios vacíos), [8]
y la sintaxis para acceder a las matrices es idéntica a la cual se puede utilizar para desreferenciar punteros.
Por ejemplo, una matriz array puede ser declarada y utilizada de la siguiente manera:

int array[5]; /* Declara 5 enteros contiguos */

int *ptr = array; /* Las matrices pueden ser utilizadas como punteros */

ptr[0] = 1; /* Los punteros se pueden indexar con la sintaxis de matrices */

*(array + 1) = 2; /* Las matrices pueden ser dereferenciadas con sintaxis de puntero */

*(1 + array) = 3; /* La adición del puntero es conmutativa */

2[array] = 4; /* El operador subíndice es conmutativo */

Esto asigna un bloque de cinco enteros y nombres de la matriz por bloques, que actúa como un puntero al
bloque. Otro uso común de los punteros es para que apunte a la memoria asignada dinámicamente desde
malloc que devuelve un bloque consecutivo de memoria de no menos que el tamaño solicitado que se
puede utilizar como una matriz.

Aunque la mayoría de los operadores sobre matrices y punteros sean equivalentes, es importante tener en
cuenta que el operador sizeof será diferente. En este ejemplo, sizeof (array) evaluará a
5*sizeof(int) (el tamaño de la matriz), mientras que sizeof(ptr) evaluará sizeof (int*), el
tamaño del propio puntero.

Los valores por defecto de una matriz se pueden declarar como:

int array[5] = {2,4,3,1,5};

Si se asume que array se encuentra en la memoria a partir de la dirección 0x1000 de una máquina little
endian de 32 bits entonces la memoria contendrá lo siguiente (los valores se encuentran en hexadecimal, así
como las direcciones):

0 1 2 3
1000 2 0 0 0
1004 4 0 0 0
1008 3 0 0 0
100C 1 0 0 0
1010 5 0 0 0

Aquí están representados cinco enteros: 2, 4, 3, 1 y 5. Estos cinco enteros ocupan 32 bits (4 bytes) cada
uno con el byte menos significativo que se almacena primero (esto es una arquitectura de CPU little endian)
y se almacenan de forma consecutiva comenzando en la dirección 0x1000.

La sintaxis de C con punteros es:

array significa 0x1000


array+1 significa 0x1004 (tener en cuenta que en realidad significa el "1" añade una vez
el tamaño de un int (4 bytes) no literalmente "más uno")
*array significa desreferenciar los contenidos de array. Teniendo en cuenta el contenido
como una dirección de memoria (0x1000), buscar el valor en esa ubicación (0x0002).
array[i] significa número de elemento i, base 0, de la matriz que se traduce en *
(array + i)

El último ejemplo es cómo acceder a los contenidos del array. Descomponiéndolo:

array + i es la posición de memoria de la (i +1)-ésimo elemento de la matriz


*(array + i) toma esa dirección de memoria y elimina referencias a acceder al valor.

Por ejemplo array[3] es sinónimo de *(array+ 3), es decir, *(0x1000 + 3*sizeof (int)),
que dice "eliminar la referencia al valor almacenado en 0x100C", en este caso 0x0001.

Lista vinculada en C
A continuación se muestra un ejemplo de definición de una lista enlazada en C.

/* la lista enlazada vacía está representada por NULL

* o algún otro valor centinela */

#define EMPTY_LIST NULL

struct link {

void *datos; /* datos de este vínculo */

struct link *proximo; /* siguiente enlace; EMPTY_LIST si no hay ninguno */

};

Nótese que esta definición puntero-recursivo es esencialmente la misma que la definición de referencia-
recursiva del lenguaje de programación Haskell:

data Link a = Nil

| Cons a (Link a)

Nil es la lista vacía y Cons a (Link a) es una cons cell de un tipo a con otro enlace también de
tipo a.

Sin embargo, la definición de referencias es de tipo comprobado y no utiliza los valores de señal
potencialmente confusos. Por esta razón, en C, las estructuras de datos normalmente se tratan a través de
funciones contenedor, que son cuidadosamente verificadas para su corrección.

Pasaje por dirección utilizando punteros

Los punteros se pueden usar para pasar variables por su dirección, lo que permite cambiar su valor. A modo
de ejemplo, se considera el siguiente código en C:

#include <stdio.h>

/* se puede cambiar una copia de int n dentro de la función sin afectar el código de llamada
*/

void passbyvalue(int n) {

n = 12;

/* En su lugar, se pasa un puntero a m. No se crea ninguna copia m de sí mismo */

void passbyaddress(int *m) {

*m = 14;

int main(void) {

int x = 3;

/* pasar una copia del valor de x como argumento */

passbyvalue(x);

// el valor ha cambiado dentro de la función, pero x sigue siendo 3 de aquí


posteriormente

/* pasar la dirección de x como argumento */

passbyaddress(&x);

// en realidad x fue cambiada por la función y ahora aquí es igual a 14

return 0;

Asignación dinámica de memoria


Los punteros se utilizan para almacenar y administrar las direcciones de los bloques de memoria asignados
dinámicamente. Dichos bloques se utilizan para almacenar objetos o conjuntos de objetos de datos. Los
lenguajes más estructurados y orientados a objetos proporcionan un área de memoria, llamada el montón o
tienda libre, de la que objetos dinámicamente asignados.

El código de ejemplo C siguiente ilustra cómo se asignan dinámicamente objetos de estructura y referencia.
La biblioteca C estándar proporciona la función malloc() para asignar bloques de memoria desde el
montón. Se necesita el tamaño de un objeto para asignarlo como parámetro y devolver un puntero a un
bloque recién asignado de memoria adecuado para almacenar el objeto, o se devuelve un puntero nulo si la
asignación falla.

/* Item de inventario de partes */

struct Item {

int id; /* Número de parte */

char * name; /* Nombre de parte */

float cost; /* Costo */

};

/* Asignar e inicializar un nuevo objeto de elemento */

struct Item * make_item(const char *name) {

struct Item * Item;

/* Asignar un bloque de memoria para un nuevo objeto de elemento */

Item = (struct Item *)malloc(sizeof(struct Item));

if (Item == NULL)

return NULL;

/* Inicializa los miembros del nuevo elemento */

memset(Item, 0, sizeof(struct Item));

Item->id = -1;

Item->name = NULL;

Item->cost = 0.0;

/* Guarde una copia del nombre en el nuevo elemento */

Item->name = (char *)malloc(strlen(name) + 1);

if (Item->name == NULL) {

free(Item);

return NULL;

strcpy(Item->name, name);

/* Devuelve el objeto de artículos recientemente creados */

return Item;

El código siguiente muestra cómo se desasignan dinámicamente objetos de memoria, es decir, retorna al
montón o tienda libre. La biblioteca C estándar proporciona la función free() para cancelar la
asignación de un bloque de memoria previamente asignado y retornar de nuevo al montón.

/* Desasignar un objeto Item */

void destroy_item(struct Item *item) {

/* Check for a null object pointer */

if (item == NULL)

return;

/* Desasignar la cadena de nombre guardado en el Item */

if (item->name != NULL) {

free(item->name);

item->name = NULL;

/* Desasignar el propio objeto Item */

free(item);

Hardware asignado en memoria

En algunas arquitecturas de computación, los punteros pueden ser utilizados para manipular directamente
de memoria o dispositivos asignados a la memoria.

La asignación direcciones a los punteros es una herramienta invaluable en la programación de


microcontroladores. A continuación se muestra un simple ejemplo de declaración de un puntero de tipo int
y la inicialización a una dirección hexadecimal en este ejemplo el constante 0x7FFF:

int *hardware_address = (int *)0x7FFF;

A mediados de los años 80, usar la BIOS para acceder a las capacidades de video de PC era lento. Las
aplicaciones que se encontraban en pantalla intensiva normalmente se utiliza para acceder a la memoria de
vídeo CGA directamente mediante colada las constantes hexadecimales 0xb8000 a un puntero a un array
de 80 valores int de 16 bits sin signo. Cada valor consistía en un código ASCII en el byte bajo y un color
en el byte alto. Por lo tanto, para poner la letra 'A' en la línea 5, columna 2 blanco sobre azul luminoso, uno
podría escribir código como el siguiente:

#define VID ((unsigned short (*)[80])0xB8000)

void foo() {

VID[4][1] = 0x1F00 | 'A';

Punteros con tipo y fundición


En muchos lenguajes, los punteros tienen la restricción adicional de que el objeto que apuntan tiene un tipo
específico. Por ejemplo, un indicador puede ser declarado para apuntar a un número entero; será el lenguaje
el que trate de evitar que el programador apunte a objetos que no fuesen números enteros, tales como
números de coma flotante, eliminando algunas errores.

Por ejemplo, en C

int *money;

char *bags;

money sería un puntero entero y bags sería un puntero char. Lo siguiente daría una advertencia del
compilador de "asignación desde un tipo de puntero" bajo GCC

bags = money;

porque money y bags fueron declarados con diferentes tipos. Para suprimir la advertencia del
compilador, debe quedar explícita de que realmente se desea hacer la cesión por encasillamiento.

bags = (char *)money;

que dice emitir el puntero entero de money a un puntero char y asignarlo a bags.
Un proyecto de la norma C estándar de 2005 requiere que echando un puntero derivado de un tipo a uno
de otro tipo debía mantener la corrección de alineación para ambos tipos (6.3.2.3 Punteros, par 7):9 ​

char *external_buffer = "abcdef";

int *internal_data;

internal_data = (int *)external_buffer; // COMPORTAMIENTO INDEFINIDO si "el puntero


resultante

// no está correctamente alineado"

En lenguajes que permiten la aritmética de punteros, dicha aritmética en punteros tiene en cuenta el tamaño
del tipo. Por ejemplo, la adición de un número entero a un puntero produce otro puntero que apunta a una
dirección que es superior en número de veces que el tamaño del tipo. Esto nos permite calcular fácilmente
la dirección de elementos de una matriz de un tipo determinado, como se demostró en el ejemplo matrices
C descripto arriba. Cuando un puntero de un tipo se convierte en otro tipo de un tamaño diferente, el
programador debe esperar que el puntero aritmético se calcule de manera diferente. En C, por ejemplo, si la
matriz money comienza a 0x2000 y sizeof (int) es 4 bytes mientras que sizeof (char) es de
1 byte, entonces (money+1) apuntará a 0x2004 pero (bags+1) apuntará a 0x2001. Entre otros
riesgos de la fundición se incluyen la pérdida de datos, cuando los datos "anchos" se escribe en ubicaciones
"estrechas" (por ejemplo, bags[0] = 65537;), se obtienen resultados inesperados cuando hay
valores de desplazamiento de bits, y problemas de comparación, sobre todo entre valores con signo vs
valores sin signo.

Aunque por lo general sea imposible determinar en tiempo de compilación que arroja son seguros, algunos
lenguajes almacenan el tipo de información en tiempo de ejecución que puede ser utilizado para confirmar
que estos peligrosos moldes son válidos en tiempo de ejecución. Otros lenguajes simplemente aceptan una
aproximación conservadora de moldes seguros, o ninguno en absoluto.

Haciendo más seguros a los punteros


Como un puntero permite que un programa intente acceder a un objeto que puede no estar definido, dichos
punteros pueden ser el origen de una variedad de errores de programación. Sin embargo, la utilidad de los
punteros es tan grande que puede ser difícil realizar tareas de programación sin ellos. En consecuencia,
muchos lenguajes han creado construcciones diseñadas para proporcionar algunas de las características
útiles de los punteros sin algunas de sus trampas, también denominadas algunas veces peligros de punteros.
En este contexto, los punteros que se dirigen directamente a la memoria (como se usa en este artículo) se
conocen como punteros crudos o sin procesar, en contraste con punteros inteligentes u otras variantes.

Uno de los mayores problemas con los punteros es que al poderse manipular directamente como un
número, se pueden hacer que este apunte a direcciones no utilizadas o a datos que se está utilizando para
otros fines. Muchos lenguajes, incluyendo lenguajes de programación funcionales y los últimos lenguajes
imperativos como Java, reemplazan los punteros con un tipo más opaco de referencia, típicamente referido
simplemente como referencia, que solo puede ser usado para referirse a los objetos y no manipula a los
números, previniendo este tipo de error. La indexación de una matriz se trata como un caso especial.

Un puntero que no tenga ninguna dirección asignada al mismo se denomina puntero salvaje. Cualquier
intento de utilizar estos punteros no inicializados puede causar un comportamiento inesperado, ya sea
porque el valor inicial no es una dirección válida, o porque su uso puede dañar otras partes del programa.
El resultado suele ser un fallo de segmentación, violación de almacenamiento o rama natural (si se utiliza
como un puntero de función o de dirección de rama).
En sistemas con asignación de memoria explícita, es posible crear un puntero de referencia colgante para
des-asignar la dirección de memoria que apunta dentro. Este tipo de puntero es peligroso y sutil, ya una
región de memoria des-asignada puede contener los mismos datos como lo hizo antes de que se cancele la
asignación, pero puede ser reasignado a continuación y se sobrescriben con código ajeno, desconocido para
el código anterior. Los lenguajes con recolector de basura previenen este tipo de error porque des afectación
se realiza automáticamente cuando no hay más referencias en el alcance.

Algunos lenguajes, como C++, soportan punteros inteligentes, que utilizan una forma simple de conteo de
referencias con el fin de ayudar a la asignación de un registro de la memoria dinámica, además de actuar
como referencia. En la ausencia de ciclos de referencia, donde un objeto se auto refiere indirectamente
mediante una secuencia de punteros inteligentes, éstos eliminan la posibilidad de punteros colgantes y
pérdidas de memoria. Las cadenas en Delphi soportan, de forma nativa, recuento de referencias.

Puntero nulo
Un puntero nulo tiene un valor reservado para indicar que el puntero no se refiere a un objeto válido. Los
punteros nulos se utilizan habitualmente para representar las condiciones tales como el final de una lista de
longitud desconocida o el fracaso para llevar a cabo algún tipo de acción, lo que el uso de punteros nulos se
puede comparar con los tipos que aceptan valores NULL y el valor de nada en un tipo de opción.

Frecuentemente, los punteros nulos se consideran similares a los valores nulos en las bases de datos
relacionales, pero tienen una semántica algo diferente. En la mayoría de los lenguajes de programación, un
puntero nulo significa "ningún valor", mientras que en una base de datos relacional, un valor nulo significa
"valor desconocido". Esto conduce a importantes diferencias en la práctica: en la mayoría de los lenguajes
de programación consideran iguales dos punteros nulos se, pero no lo son dos valores nulos en las bases de
datos relacionales (no se sabe si son iguales, ya que representan valores desconocidos).

En algunos entornos de lenguaje de programación (al menos, por ejemplo, una implementación de Lisp
propietaria[cita requerida]), el valor utilizado como puntero nulo (llamado nil en Lisp) puede, en realidad,
ser un puntero a un bloque de datos internos de utilidad para la aplicación (pero no accesible explícitamente
desde los programas de usuario), permitiendo así que el mismo registro sea utilizado como una constante
útil y una forma rápida de acceder a partes internas de aplicación. Esto se conoce como vector nil
(‘nulo’).

En C, dos punteros nulos de cualquier tipo están garantidos para comparar iguales tipo de datos10 ​ El
macro NULL es una implementación definida por una constante de puntero NULL,6 ​que en C99 se puede
expresar portablemente como un valor entero 0 convertido implícita o explícitamente al tipo void*.11 ​

Típicamente, desreferenciar el puntero NULL significa intentar leer o escribir en la memoria que no se
asigna, esto desencadena un fallo de segmentación o violación de acceso. Esto puede representar en sí
mismo, para el desarrollador, un fallo en el programa, o se transforma en una excepción que puede
capturarse. Sin embargo, hay ciertas circunstancias en las que esto no es el caso. Por ejemplo, en modo en
x86 real, la dirección 0000:0000 es legible y por lo general escribible, de ahí que la eliminación de
referencias de puntero nulo sea una acción perfectamente válida pero, en general, no deseada que puede
conducir a un comportamiento indefinido, pero no causa un crash en la aplicación. Además, tener en cuenta
que hay ocasiones en que la desreferenciación NULL es intencional y bien definida, como por ejemplo el
código del BIOS, escrito en C, para dispositivos x86 de 16 bits en modo real, puede escribir la IDT en la
dirección física 0 de la máquina, desreferenciando al puntero a NULL para la escritura. También es posible
que el compilador optimice desde lejos el puntero de dereferencia `NULL`, evitando un fallo de
segmentación pero sin causar otro tipo de comportamiento no deseado (http://blog.llvm.org/2011/05/what-e
very-c-programmer-should-know.html).
En C++, ya que el macro NULL fue heredado de C, tradicionalmente se prefere el literal entero para cero
para representar una constante de puntero nulo.12 ​ Sin embargo, C++11 ha introducido una constante
nullptr explícita que se utilizará en su lugar.

No se debe confundir un puntero nulo con un puntero no inicializado: Un puntero nulo está garantizado
para comparar desigual a cualquier puntero que apunta a un objeto válido. Sin embargo, en función del
idioma y la aplicación, un puntero no inicializado tiene, o bien un valor indeterminado (al azar o sin
sentido), o un valor específico que no tiene porqué ser necesariamente una especie de puntero nulo
constante.

En 2009, C. A. R. Hoare declaró13 14​ ​


que en 1965 inventó la referencia nula como parte del lenguaje
Algol W, aunque, desde 1959, NIL hubiera existido en Lisp. En esa referencia de 2009 Hoare describe su
invención como un "error de millones de dólares":

A mi error yo lo llamo error de mil millones de dólares. Fue la invención, en 1965, de la


referencia nula. En ese momento, yo estaba diseñando el primer sistema de tipo integral para
las referencias en un lenguaje orientado a objetos (ALGOL W). Mi objetivo era asegurar que
todo uso de referencias debe ser absolutamente seguras, con la comprobación realizada
automáticamente por el compilador. Pero no pude resistir la tentación de poner en una
referencia nula, simplemente porque era muy fácil de implementar. Esto ha dado lugar a
innumerables errores, vulnerabilidades y fallos del sistema, que probablemente han causado
mil millones de dólares de dolor y daños en los últimos cuarenta años.

Debido a que un puntero nulo no apunta a un objeto significativo, por lo general, (pero no siempre) intentar
eliminar la referencia a un puntero nulo provoca un error en tiempo de ejecución o la inmediata caída del
programa.

En C, no está definido el comportamiento de eliminación de referencias a un puntero nulo15 ​


Muchas implementaciones causan este tipo de código de lugar a que el programa se
detenga con una violación de acceso, porque se elige la representación de puntero nulo
para ser una dirección que no es asignada por el sistema para el almacenamiento de
objetos. Sin embargo, este comportamiento no es universal.
En Java, acceder a una referencia nula desencadena una NullPointerException (h
ttp://java.sun.com/j2se/1.5.0/docs/api/java/lang/NullPointerExcep
tion.html) (NPE), que puede detectar el código de gestión de errores, pero en la
práctica lo que se prefiere es asegurar que nunca ocurran tales excepciones.
En. NET, acceder a la referencia nula desencadena una excepción
NullReferenceException. Aunque generalmente la captura de éstos se considera una mala
práctica, se puede atrapar este tipo de excepción y manipularse por el programa.
En Objective-C, los mensajes se pueden enviar a un objeto nil (que es esencialmente un
puntero nulo) sin causar que el programa se interrumpa; el mensaje es simplemente
ignorado, y el valor de retorno (si lo hay) es nil o 0, dependiendo del tipo.16 ​

En lenguajes con una arquitectura de etiquetado, posiblemente, un puntero nulo pueda ser reemplazado con
una unión marcada que impone la manipulación explícita del caso excepcional, de hecho, un puntero nulo,
posiblemente, pueda ser visto como un puntero etiquetado con una etiqueta computarizada.

Puntero auto relativo


El término puntero auto relativo puede referirse a un puntero cuyo valor se interpreta como un
desplazamiento desde la dirección del propio puntero, por lo que, si una estructura de datos, , tiene un
elemento puntero auto relativo, , que apunta a una porción de sí mismo, entonces puede ser
17
reubicado en la memoria sin tener que actualizar el valor de . ​
La patente citada también utiliza el
término puntero auto relativo para significar la misma cosa. Sin embargo, el significado de ese término se
ha utilizado en otras formas:

Es de uso frecuente significar un desplazamiento de la dirección de una estructura y no de


la dirección de la propia puntero.[cita requerida]
Se ha utilizado para significar un puntero que contiene su propia dirección, que puede ser
útil para la reconstrucción en cualquier región arbitraria de la memoria una colección de
estructuras de datos que apuntan la una a la otra.18 ​

Puntero base
Un puntero base es un puntero cuyo valor es un desplazamiento desde el valor de otro puntero. Esto
puede ser usado para almacenar y cargar los bloques de datos, asignando la dirección de comienzo del
bloque al puntero base.19 ​

Indirección múltiple
En algunos lenguajes, un puntero puede hacer referencia a otro puntero, lo que requiere múltiples
operaciones de des referenciación para llegar al valor original. Mientras que cada nivel de indirección
puede añadir un costo de rendimiento, es a veces necesario para proporcionar un comportamiento correcto
para estructuras de datos complejas. Por ejemplo, en C es típico definir una lista enlazada, en términos de
un elemento que contiene un puntero al siguiente elemento de la lista:

struct element

struct element * next;

int value;

};

struct element * head = NULL;

Esta aplicación utiliza un puntero al primer elemento de la lista como un sustituto para la lista completa. Si
se añade un nuevo valor al principio de la lista, debe cambiarse la cabecera para que apunte al nuevo
elemento. Dado que argumentos C siempre se pasan por valor, utilizando direccionamiento indirecto doble
se permite la inserción de implementarse correctamente, y tiene el efecto secundario deseable de eliminar el
código de casos especiales para hacer frente a las inserciones en la parte delantera de la lista:

// Dada una lista ordenada en la * cabecera, insertar el elemento elemento en la primera

// lugar donde todos los elementos anteriores tienen menor o igual valor.

void insert(struct element **head, struct element *item)

struct element ** p; // p apunta a un puntero de un elemento

for (p = head; *p != NULL; p = &(*p)->next)

if (item->value <= (*p)->value)

break;

item->next = *p;

*p = item;

// El llamador hace esto:

insert(&head, item);

En este caso, si el valor de item es menor que el de la head, se actualizará el llamador head,
correctamente a la dirección del nuevo ítem.

Un ejemplo básico es en el argumento argv de la función principal en C (y C ++), que se da en el prototipo


como char **argv - esto es debido a que la variable argv es en sí es un puntero a un arreglo de
cadenas (un arreglo de arreglos), por lo que *argv es un puntero a la cadena 0 (por convención al nombre
del programa), y **argv es el carácter 0 de la cadena 0.

Puntero a función
En algunos lenguajes, un puntero puede hacer referencia a código ejecutable, es decir, puede apuntar a una
función, método o procedimiento. Un puntero a función almacenará la dirección de una función que sea
invoca. Si bien este mecanismo se puede utilizar para llamar a funciones de forma dinámica, muchas veces
es una técnica favorita de virus y otros autores de software malicioso.

int a, b, x, y;

int sum(int n1, int n2); // Función con dos parámetros enteros que devuelve un valor
entero

int (*fp)(int, int); // Puntero de función que puede apuntar a una función como la
suma

fp = &sum; // fp ahora apunta a la función suma

x = (*fp)(a, b); // La función suma llama con argumentos a y b

y = sum(a, b); // La función suma llama con argumentos a y b

Puntero salvaje
Un puntero salvaje es un puntero que no se ha sido inicializado (es decir, un puntero salvaje no ha tenido
ninguna dirección asignada a él) y puede provocar un fallo en el programa o comportarse de manera
extraña. En los lenguajes de programación Pascal o C, los punteros que no están específicamente
inicializados pueden apuntar a direcciones impredecibles en la memoria.

El siguiente código de ejemplo muestra un puntero salvaje:

int func(void)

char *p1 = malloc(sizeof(char)); /* (valor (indefinido) de algún lugar del montón */

char *p2; /* puntero salvaje (sin inicializar) */

*p1 = 'a'; /* Esto está bien, asumiendo que malloc() no haya devuelto NULL. */

*p2 = 'b'; /* Así se invoca un comportamiento indefinido */

Aquí, p2 puede apuntar a cualquier lugar de la memoria, por lo que la realización de la tarea * p2 =
'b' puede corromper una zona desconocida de la memoria o provocar un fallo de segmentación.

Simulación utilizando un índice de matriz


Es posible simular el comportamiento del puntero usando un índice a un matriz (normalmente
unidimensional)
Principalmente para lenguajes que no soportan punteros de manera explícita pero realizan soporte de
matrices, la matriz se puede considerar y procesar como si fuera el rango de memoria completo (dentro del
alcance de la matriz particular) y cualquier índice a ella puede considerarse como equivalente a un registro
de propósito general en lenguaje ensamblador (que apunta a los bytes individuales pero cuyo valor real es
relativo al comienzo de la matriz, no su dirección absoluta en memoria). Suponiendo que la matriz es, por
ejemplo, una estructura de datos de caracteres contiguos de 16 megabytes, los bytes individuales (o una
cadena de bytes contiguos dentro de la matriz) puede ser directamente dirigida y manipulada usando el
nombre de la matriz con un entero sin signo de 31 bits como el puntero simulado (esto es bastante similar al
ejemplo de arreglos de C mostrado anteriormente). La aritmética de punteros puede simularse mediante la
adición o sustracción del índice, con una sobrecarga adicional mínima en comparación con la verdadera
aritmética de punteros.

Incluso es teóricamente posible, utilizando la técnica anterior, juntar con un simulador de juego de
instrucciones adecuadas para simular cualquier código de máquina o el intermedio (bytescode) de cualquier
procesador/lenguaje en otro lenguaje que no admite punteros en absoluto (por ejemplo Java / JavaScript).
Para lograr esto, el código binario se puede cargar inicialmente en los bytes contiguos de la matriz para que
el simulador "lea", interprete y se ejecute enteramente dentro de la memoria contenida de la misma matriz.
Si es necesario, generalmente se puede activar comprobación de límites por el compilador, a los efectos de
evitar por completo los problemas de desbordamiento de búfer (o si no, codificar a mano en el simulador).

Punteros en lenguajes de programación


En programación es posible crear procedimientos, estructuras, variables, constantes entre otras cosas,
cuando es ejecutada cada una de estas estructuras tiene una dirección en memoria, es conveniente conocer
este tipo de información cuando se trabaja con lenguajes que soportan los punteros de manera no abstracta.

A continuación veremos cómo trabajan los punteros en variables, estructuras y uniones.


Los punteros que
apunten a estas estructuras de almacenamiento estarán dirigidos a los primeros miembros de cada estructura,
unión o matriz.

Estructuras

Las estructuras de datos reservan segmentos en memoria separados para cada miembro, esto significa que
cada miembro tiene su propia dirección en memoria (su propio puntero).

Podemos representar gráficamente una estructura de datos llamada "Estructura" de la siguiente manera:

1 1 4 Bytes.

+-----+-----+---------+

| A | B | C | Miembros.

+-----+-----+---------+

0x1 0x2 0x3 Dirección.

Puntero base de la estructura completa.

Como se puede ver, existen 3 métodos de tipo numérico en memoria llamados "A","B" y "C", los dos
primeros métodos (A y B) son de tipo Byte y tienen reservado 1 byte cada uno en distintos segmentos en la
memoria, por lo que tienen diferentes direcciones (0x01 y 0x02 en su respectivo orden).
La dirección de memoria de la estructura en general es igual a la dirección de su primer miembro, la
dirección de su segundo miembro es igual a la dirección de su primer miembro, mas su tamaño en bytes y
la dirección del tercer miembro es igual a la dirección del primer miembro, más el tamaño de los dos
miembros anteriores y así sucesivamente.

Uniones

La principal diferencia entre una unión y una estructura es la memoria utilizada, a diferencia de las
estructuras, las uniones solo utilizan la cantidad de memoria de su miembro más grande, y todos los
miembros comparten una única dirección en memoria.

Por ejemplo:

4 Bytes.

+-----------+

| A B C | Miembros.

+-----------+

0x1 Dirección.

Los miembros "A" y "C" solo pueden contener valores entre 0 y 255 (Tipo Byte), el miembro "B" puede
tener valores entre 0 y 4.294.967.295 (Tipo Entero), si el miembro "A" cambia su valor a 13, también lo
hacen los miembros "B" y "C" (A,B y C son igual a 13), si el miembro "B" cambia su valor a 4000, los
miembros "A" y "C" se quedan únicamente en 160 ya que tratan de traducir el valor 4000 a byte (A y C
son igual a 160, B = 4000), el tamaño total de la unión es de 4 bytes debido a que los miembros comparten
la misma memoria (la unión pesa lo mismo que su miembro con mayor reserva de memoria).

Matrices

Las matrices son casi igual que las estructuras, reservan memoria para cada matriz, la dirección en memoria
de cada miembro es consecutiva a la suma de sus anteriores, mas sus tamaños y la dirección de la matriz
total es igual a la del primer miembro, la única diferencia entre una matriz y una estructura es que cada
matriz tiene el mismo tipo de dato (los miembros de una estructura pueden ser de distintos tipos).

Podemos representar a una matriz con rango de 3 (tipo entero) en memoria de la siguiente manera.

4 4 4 Bytes.

+-----+-----+-----+

| 0 | 1 | 2 | Identificador.

+-----+-----+-----+

0x1 0x5 0x9 Dirección.

Como se puede apreciar, cada miembro tiene una dirección en memoria con 4 bytes de diferencia entre sí.
El puntero base de la matriz entera es la dirección de su primer matriz (Matriz@ = Matriz[0]@).

Soporte en lenguajes de programación

Ada
Ada es un lenguaje fuertemente tipado en el cual todos los punteros son tipados y solamente se permiten
conversiones de tipos de seguros. Todos los indicadores están por defecto inicializado en null, y
cualquier intento de acceder a la información a través de un puntero a null provoca una excepción. En
Ada, los punteros se llaman tipos de acceso. Ada-83 no permitía aritmética en tipos de acceso (aunque los
distintos compiladores la suministren como una funcionalidad fuera del patrón), pero Ada-95 soporta tipos
aritméticos en tipos de acceso seguro por el paquete System.Storage_Elements.

BASIC

Varias versiones antiguas de BASIC para la plataforma Windows tenían soporte para STRPTR() para
devolver la dirección de una cadena, y para VARPTR() para devolver la dirección de una variable. Visual
Basic 5 también tenía soporte para OBJPTR() para devolver la dirección de una interfaz de objeto, y para
un operador ADDRESSOF para devolver la dirección de una función. Los tipos de todos estos son
números enteros, pero sus valores son equivalentes a estos valores por tipos de puntero.

Sin embargo, dialectos más recientes de BASIC, como FreeBASIC o BlitzMax, tienen implementaciones
de puntero exhaustivas. En FreeBASIC, la aritmética en punteros ANY (equivalente al void* de C) son
tratados como si el puntero ANY fuera un ancho de bytes. A diferencia de C, los punteros ANY no pueden
ser desreferenciados. Además, la conversión entre ANY y cualquier otro tipo de punteros no generará
ninguna advertencia.

dim as integer f = 257

dim as any ptr g = @f

dim as integer ptr i = g

assert(*i = 257)

assert( (g + 4) = (@f + 1) )

C y C++

En C y C++ los punteros son variables que almacenan direcciones y pueden ser null. Cada puntero tiene un
tipo que apunta, pero el programador puede convertir libremente entre tipos de puntero (pero no entre un
puntero a función y no la función de tipo de puntero). Un tipo de puntero especial llamado el "vacío
puntero" permite que apunta a cualquier tipo de variable (no función), pero es limitada por el hecho de que
no se puede eliminar las referencias de forma directa. La dirección en sí a veces puede ser manipulada
directamente mediante colada un puntero hacia y desde un tipo entero de tamaño suficiente, aunque los
resultados se han definido por la implementación y de hecho pueden causar un comportamiento indefinido;
mientras que los estándares anteriores a C no tengan un tipo entero que garantice que sea lo suficientemente
grande, C99 especifica el nombre definido uintptr_ʈ typedef en < stdint.h>, pero una aplicación
no tiene por qué proporcionarla.

C++ es totalmente compatible con los punteros de C y el typecasting de C. También es compatible con una
nueva agrupación de operadores de typecasting para ayudar a capturar a algunos casts peligrosos no
deseados en tiempo de compilación. Desde C++11, la librería estándar de C++ también proporciona
punteros inteligentes (unique_ptr, shared_ptr y weak_ptr) que se pueden utilizar en algunas
situaciones como una alternativa segura a los punteros primitivos de C. C++ también es compatible con
otro tipo de referencia, muy diferente de un puntero, llamado simplemente una referencia o tipo de
referencia.
La aritmética de punteros, es decir, la capacidad de modificar la dirección de destino de un puntero con
operaciones aritméticas (así como comparaciones de magnitud), está restringido por el lenguaje estándar
para permanecer dentro de los límites de un solo objeto arreglo (o justo después de él), porque de otro
modo provocaría un comportamiento indefinido. Sumando o restando de un puntero que desplaza por un
múltiplo del tamaño del tipo de datos que apunta. Por ejemplo, la adición de 1 a un puntero a valores
enteros de 4 bytes incrementará el puntero por 4. Esto tiene el efecto de incrementar el puntero para señalar
en el siguiente elemento en una matriz contigua de números enteros-que muchas veces presenta un
resultado previsto. La aritmética de punteros no se puede realizar en punteros void porque el tipo de vacío
no tiene tamaño, y por lo tanto no puede añadir la dirección de punteros, aunque gcc y otros compiladores
realizan operaciones aritméticas de byte de void* como una extensión no estándar. Para trabajar
"directamente" con bytes, generalmente arrojan punteros a BYTE*, o unsigned char* si BYTE no
está definido en la biblioteca estándar que se utiliza.

La aritmética de punteros le provee al programador una única manera de tratar con diferentes tipos:
sumando y restando el número de los elementos requeridos en lugar del actual desplazamiento en bytes.
(aunque el puntero sea char, el char se define como tener siempre un tamaño de un byte, permite el
desplazamiento del elemento de la aritmética de punteros en la práctica sea igual a un desplazamiento de
bytes) En particular, la definición C declara explícitamente que la sintaxis de a[n], que es el elemento n-
ésimo de la matriz de a, es equivalente a *(a+n), que es el contenido del elemento apuntado por a+n.
Esto implica que n[a] es equivalente a a[n], y se puede escribir, por ejemplo, a[3] o 3[a] por igual
para acceder al cuarto elemento de una matriz a.

Aunque poderosa, la aritmética de punteros puede ser una fuente de errores informáticos. Este tiende a
confundir a los programadores novatos, forzándolos a diferentes contextos: una expresión puede ser una
aritmética ordinaria uno o una aritmética de punteros uno, ya veces es fácil confundir uno con el otro. En
respuesta a esto, muchas lenguajes informáticos modernos de alto nivel (por ejemplo Java) no permiten el
acceso directo a memoria utilizando direcciones. Además, el dialecto seguro de C, Cyclone, aborda muchos
de los problemas con los punteros. Véase lenguaje de programación C de examinar más.

El puntero void, o void*, es compatible en ANSI C y C++ como tipo de genérico puntero. Un puntero
a void puede almacenar una dirección a cualquier tipo de datos no-función, y, en C, se convierte
implícitamente a cualquier otro tipo de puntero en asignación, pero se debe convertir explícitamente si es
desreferenciado en línea.
K&R C utiliza char* para el propósito de "puntero de tipo agnóstico" (antes de
ANSI C).

int x = 4;

void* q = &x;

int* p = q; /* void* convierte implícitamente a int*: válido en C, pero no en C++ */

int i = *p;

int j = *(int*)q; /* cuando se desreferencia en línea, no hay conversión implícita */

C++ no permite la conversión implícita de void* a otros tipos de puntero, incluso en las asignaciones.
Esta fue una decisión de diseño para evitar vaciados descuidados e incluso no deseados, aunque la mayoría
de los compiladores solo muestren advertencias como salida, no errores, cuando se encuentran con otros
cast.

int x = 4;

void* q = &x;

// int* p = q; Esto falla en C++: no hay conversión implícita de void*

int* a = (int*)q; // cast estilo C

int* b = static_cast<int*>(q); // C++ cast

En C++, no hay void& y (referencia a void) para complementar void* (puntero a void), ya que las
referencias se comportan como alias a las variables que apuntan, y nunca puede ser una variable cuyo tipo
es void.

C#

En el lenguaje de programación C#, los punteros son compatibles solo bajo ciertas condiciones: cualquier
bloque de código que incluya punteros debe ser marcada con la palabra clave unsafe. Generalmente,
tales bloques requieren permisos de seguridad superiores a código pointerless que se le permitiera correr. La
sintaxis es esencialmente la misma que en C++, y la dirección apuntada se puede gestionar tanto memoria
administrada como no administrado. Sin embargo, los punteros a memoria administrada (cualquier puntero
a un objeto administrado) deben ser declarado usando la palabra clave fixed, lo que evita que la
recolector de basura del movimiento del objeto apuntado, como parte de la gestión de memoria mientras el
puntero está a su alcance, lo que mantiene válida la dirección del puntero.

Una excepción a esto es utilizar la estructura de IntPtr, que es un equivalente administrado seguro para
int*, y no requiere código no seguro. Este tipo suele aparecer cuando el uso de métodos de las
System.Runtime.InteropServices, por ejemplo:

// Obtener 16 bytes de memoria de la memoria no administrada del proceso

IntPtr pointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(16);

// Hacer algo con la memoria asignada

// Liberar la memoria asignada

System.Runtime.InteropServices.Marshal.FreeHGlobal(pointer);

El .NET Framework incluye muchas clases y métodos en el sistema y los espacios de nombres
System.Runtime.InteropServices (como la clase Marshal) que convierten tipos de.NET
(por ejemplo, System.String) desde y hacia muchos tipos no administrados y punteros (por ejemplo,
LPWSTR o void *) para permitir la comunicación con código no administrado.

COBOL

El lenguaje de programación COBOL soporta punteros a variables. Los objetos primitivos o datos de
grupos (graban) objetos de datos declarados dentro de la LINKAGE SECTION de un programa son
inherentemente basados en punteros, donde la única memoria asignada en el programa es el espacio para la
dirección del elemento de datos (normalmente una palabra de memoria individual), basados en punteros. En
el código fuente del programa, estos elementos de datos son utilizados como cualquier otra variable
WORKING-STORAGE, pero sus contenidos están indirecta e implícitamente accedidos a través de sus
punteros LINKAGE.

El espacio de memoria para cada señaló a objeto de datos se suelen asignar dinámicamente utilizando las
sentencias CALL externos o a través de construcciones del lenguaje extendidos embebidas como EXEC
CICS o sentencias EXEC SQL

Las versiones extendidas de COBOL también proporcionan variables de puntero declarados con cláusulas
USAGE IS POINTER. Los valores de estas variables de puntero se establecen y modifican usando SET y
declaraciones SET ADDRESS.
Algunas versiones extendidas de COBOL también proporcionan variables de PROCEDURE-POINTER
triple, que son capaces de almacenar las direcciones de código ejecutable.

PL/I

El lenguaje PL/I proporciona soporte completo para punteros a todos los tipos de datos (incluyendo
punteros a estructuras), recursividad, multitarea, manejo de cadenas, y amplias funciones incorporadas. PL/I
era un salto absoluto hacia adelante en comparación con los lenguajes de programación de su tiempo.
[cita requerida]

El lenguaje de programación D es un derivado de C y C++, que es totalmente compatible con los punteros
de C y los typecasting de C.

Eiffel

El lenguaje Eiffel orientado a objetos soporta punteros en forma de referencias, que se escriben y no
permiten ningún tipo de aritmética de punteros. El estándar ECMA para Eiffel incluye un mecanismo de
"tipo adjunto" que pretende garantizar un void seguro.

Fortran

Fortran-90 introdujo la capacidad de puntero inflexible de tipos. Los punteros en Fortran contienen algo
más que una simple dirección de memoria. También encapsulan los límites inferior y superior de
dimensiones de matriz, pasos (por ejemplo, para soportar a las secciones de matriz arbitrarias), y otros
metadatos. Un operador asociación, => se utiliza para asociar un puntero a una variable que tiene un
atributo TARGET. El Fortran-90 también se puede usar la declaración ALLOCATE para asociar un puntero
a un bloque de memoria. Por ejemplo, el siguiente código podría ser usado para definir y crear una
estructura de lista enlazada:

type real_list_t

real :: sample_data(100)

type (real_list_t), pointer :: next => null ()

end type

type (real_list_t), target :: my_real_list

type (real_list_t), pointer :: real_list_temp

real_list_temp => my_real_list

do

read (1,iostat=ioerr) real_list_temp%sample_data

if (ioerr /= 0) exit

allocate (real_list_temp%next)

real_list_temp => real_list_temp%next

end do

Fortran-2003 añade soporte para punteros de procedimiento. También, como parte de la función de
Interoperabilidad de C, Fortran-2003 es compatible con las funciones intrínsecas para la conversión de
punteros al estilo C a punteros Fortran y traseros.
Go

Go tiene punteros. Su sintaxis de declaración es equivalente a la de C, pero escrito al revés, terminando con
el tipo. A diferencia de C, Go tiene la recolección de basura, y no permite la aritmética de punteros. Al
igual que en C++, no existen los tipos de referencia. Algunos tipos incorporados, como los mapas y
canales, están encuadradas (es decir, internamente son punteros a estructuras mutables), y se inicializan
utilizando la función make. Como un enfoque diferente (que los tipos de referencia) a la sintaxis unificada
entre punteros y no punteros, el operador flecha (->) se ha dejado caer—es posible utilizar el operador
punto directamente en un puntero a un tipo de datos para acceder a un ámbito o método del valor
desreferenciado, como si el operador punto se utiliza en el tipo de datos subyacente. Esto, sin embargo, solo
funciona con 1 nivel de indirección.

Java

A diferencia de C, C++ o Pascal, no hay representación explícita de punteros en Java. En cambio, las
estructuras de datos más complejas como los objetos y las matrices se implementan utilizando referencias.
El lenguaje no ofrece operadores explícitos de manipulación de punteros. Aún es posible para el código
intentar eliminar la referencia de una referencia nula (puntero null), sin embargo, lo que resulta en una
excepción de tiempo de ejecución que es lanzada. El espacio ocupado por objetos de memoria no
referenciados se recupera automáticamente recolectando la basura en tiempo de ejecución.20 ​

Modula-2

Los punteros son fuertemente implementados como en Pascal, al igual que los parámetros VAR en las
llamadas a procedimiento. Modula-2 es más inflexible incluso que Pascal, con al menos vías de escape del
sistema de tipos. Algunas de las variantes de Modula-2 (como Modula-3) incluyen recolección de basura.

Oberon

Al igual que Modula-2, los punteros están disponibles. Aún hay un menor número de maneras de evadir el
sistema de tipos y así Oberon y sus variantes son aún más seguros con respecto a los punteros de Modula-2
o sus variantes. Al igual que con Modula-3, la recolección de basura es una parte de la especificación del
lenguaje.

Pascal

A diferencia de muchas lenguajes que cuentan con punteros, el estándar ISO Pascal solo permite punteros
para hacer referencia a las variables creadas dinámicamente que son anónimas y no les permiten referenciar
estándares estáticos o variables locales.21 ​ No tiene aritmética de punteros. Los punteros deben también de
tener un tipo asociado, y un puntero a un tipo no es compatible con un puntero a otro tipo (por ejemplo, un
puntero a un char no es compatible con un puntero a un entero). Esto ayuda a eliminar los problemas de
seguridad inherentes tipo con otras implementaciones de puntero, especialmente los utilizados para PL/I o
C. También elimina algunos riesgos causados por punteros colgados, pero la capacidad de dejar de lado el
espacio de forma dinámica se hace referencia mediante el procedimiento estándar dispose (que tiene el
mismo efecto que la función de la librería free encontrada en C) significa que el riesgo de punteros no se
ha eliminado por completo.22 ​
Sin embargo, en algunas implementaciones comerciales y de código abierto de compiladores de Pascal (o
derivados)-como Free Pascal,23 ​ Turbo Pascal o Object Pascal en Embarcadero Delphi—se le permite un
puntero hacer referencia a las variables estáticas o locales estándares y se puede lanzar desde un tipo
puntero a otro. Por otra parte la aritmética de punteros está restringida: añadiendo o restando de un puntero
se mueve por ese número de bytes en cualquier dirección, pero utilizando los procedimientos estándar Inc
o Dec con que se mueve el puntero por el tamaño del tipo de datos que se declara a apuntar. Un puntero
sin tipo también proporciona bajo el nombre de Pointer, que es compatible con otros tipos de puntero.

Pauscal

El lenguaje de programación Pauscal presenta un fuerte soporte de punteros, permitiendo apuntar a


variables, estructuras, procedimientos, prototipos, uniones e incluso clases y sus métodos. Los punteros se
pueden utilizar para almacenar la dirección en memoria de un objeto o para crear una referencia a este.
Pauscal utiliza los punteros para convertir tipos de datos sin necesidad de ninguna interfaz de programación
de aplicaciones (API) externa, aumentando la velocidad de ejecución de los programas ligeramente y
permitiendo que estos sean "nativos" del lenguaje.

Perl

El lenguaje de programación Perl soporta punteros, aunque raramente se utilizan, en forma de funciones de
empaquetado y desempaquetado. Estos están destinados únicamente a las interacciones simples con
bibliotecas OS compiladas. En todos los demás casos, Perl utiliza referencias, que se escriben y no permiten
ningún tipo de aritmética de punteros. Estos se utilizan para construir complejas estructuras de datos.24 ​

Véase también
Dirección constante Puntero swizzling
Puntero limitado Referencia (informática)
Desbordamiento de búfer Análisis estático de software
Función puntero Violación de almacenamiento
Puntero peligroso Puntero etiquetado
Puntero opaco Variable (programación)

Referencias
2. Milestones in Computer Science and
1. Donald Knuth (1974). «Structured Information Technology (http://books.googl
Programming with go to Statements e.com/books?id=JTYPKxug49IC&pg=PA2
("Programación Estructurada con 04&lpg=PA204&dq=Harold+Lawson+point
sentencias goto")» (https://web.archive.org/
er&source=web&ots=C5QdVz2xM8&sig=x
web/20130519122634/http://pplab.snu.ac.k
hh0SWuR-L72H6H9xgEmxD5qzBc&hl=en
r/courses/adv_pl05/papers/p261-knuth.pdf)
&ei=lCuLSbTwKY_-0AWErp2iBw&sa=X&o
(pdf). Computing Surveys (en inglés) 6 (5):
i=book_result&resnum=10&ct=result)
261-301. doi:10.1145/356635.356640 (https://dx.do
i.org/10.1145%2F356635.356640). Archivado 3. «IEEE Computer Society awards list» (http
desde el original (http://pplab.snu.ac.kr/cour s://web.archive.org/web/20110322221848/
ses/adv_pl05/papers/p261-knuth.pdf) el 19 http://awards.computer.org/ana/award/view
de mayo de 2013. PastRecipients.action?id=13). Archivado
desde el original (http://awards.computer.or
g/ana/award/viewPastRecipients.action?id
=13) el 22 de marzo de 2011. Consultado utilizar cuando se requiere una
el 16 de abril de 2015. constante. »
4. ISO/IEC 9899, cláusua 6.7.5.1, párrafo 1. 13. Tony Hoare (2009). «Null References: The
5. ISO/IEC 9899, cláusula 6.7.8, párrafo 10. Billion Dollar Mistake» (https://web.archive.
6. ISO/IEC 9899, cláusula 7.17, párrafo 3: org/web/20090119110704/http://qconlondo
NULL... que expande a una n.com/london-2009/presentation/Null+Refe
rences%3A+The+Billion+Dollar+Mistake).
implementación definida como puntero
QCon London. Archivado desde el original
constante nulo...
(http://qconlondon.com/london-2009/presen
7. ISO/IEC 9899, cláusula 6.5.3.2, párrafo 4, tation/Null+References:+The+Billion+Dolla
footnote 87: Si un valor no válido ha sido r+Mistake) el 19 de enero de 2009.
asignada al puntero, el comportamiento del Consultado el 15 de marzo de 2014.
operador unario * es indefinido... Entre los
valores válidos para desreferenciar un 14. Tony Hoare (25 de agosto de 2009). «Null
puntero por el operador unario * son un References: The Billion Dollar Mistake» (htt
puntero nulo... p://www.infoq.com/presentations/Null-Refer
ences-The-Billion-Dollar-Mistake-Tony-Hoa
8. Plauger, P J; Brodie, Jim (1992). ANSI and re). InfoQ.com.
ISO Standard C Programmer's Reference
(https://archive.org/details/ansiisostandardc 15. ISO/IEC 9899, cláusula 6.5.3.2, párrafo 4.
00plau/page/108). Redmond, WA: Microsoft 16. The Objective-C 2.0 Programming
Press. pp. 108, 51 (https://archive.org/detail Language, sección "Sending Messages to
s/ansiisostandardc00plau/page/108). nil" (http://developer.apple.com/library/mac/
ISBN  1-55615-359-7. «Un tipo de matriz no #documentation/Cocoa/Conceptual/Objecti
contiene agujeros adicionales porque veC/Chapters/ocObjectsClasses.html#//ap
todos los otros tipos de paquetes se ple_ref/doc/uid/TP30001163-CH11-SW7).
hermetizan cuando están compuestos en 17. Plantilla:Cita patente
matrices [en página 51] ». 18. Plantilla:Cita patente
9. WG14 N1124 (http://www.open-std.org/jtc1/ 19. Based Pointers (http://msdn.microsoft.com/
sc22/wg14/www/docs/n1124.pdf), C – en-us/library/57a97k4e.aspx)
Approved standards: ISO/IEC 9899 –
20. Nick Parlante, [1] (http://cslibrary.stanford.e
Programming languages – C (http://www.op
du/102/PointersAndMemory.pdf#%22Point
en-std.org/jtc1/sc22/wg14/www/standards.h
ers%20and%20Memory%22), Stanford
tml), 6 de mayo de 2005.
Computer Science Education Library (http://
10. ISO/IEC 9899, cláusula 6.3.2.3, párrafo 4. cslibrary.stanford.edu#), pp. 9–10 (2000).
11. ISO/IEC 9899, cláusula 6.3.2.3, párrafo 3. (en inglés)
12. Stroustrup, Bjarne (marzo de 2001). 21. ISO 7185 Pascal Standard (unofficial
«Chapter 5: Pointers, Arrays, and copy), section 6.4.4 Pointer-types (http://sta
Structures: 5.1.1: Zero». The C++ ndardpascal.org/iso7185.html#6.4.4%20Po
Programming Language (14ta impresión de inter-types) y subsecuentes.
la 3ra edición). Estados Unidos y Canadá: 22. J. Welsh, W. J. Sneeringer, and C. A. R.
Addison–Wesley. p. 88 (https://archive.org/ Hoare, "Ambiguities and Insecurities in
details/cprogramminglang00stro_0/page/8 Pascal," Software Practice and Experience
8). ISBN  0-201-88954-4. «En C, ha sido 7, pp. 685–696 (1977)
popular definir un macro NULL para 23. Free Pascal Language Reference guide,
representar el puntero cero. Debido a que section 3.4 Pointers (http://www.freepascal.
en C++ es más estricta la comprobación de org/docs-html/ref/refse15.html#x43-490003.
tipo, el uso del 0 plano, en lugar de 4)
cualquier macro NULL sugerido, conduce a
un menor número de problemas. Si se 24. // Making References (Perl References and
necesita definir NULL. utilizar  : const nested data structures) (en inglés) (http://pe
rldoc.perl.org/perlref.html#Making-Referenc
int NULL = 0;
El calificador const (§
es)
5.4) previene redefinición accidental de
NULL y se asegura de que NULL se puede
Enlaces externos
Punteros en C/C++ (http://c.conclase.net/curso/index.php?cap=012) y correspondencia
entre arrays y punteros. (http://c.conclase.net/curso/index.php?cap=012b)
Memoria dinámica en C: malloc, (http://c.conclase.net/librerias/funcion.php?fun=malloc)
realloc (http://c.conclase.net/librerias/funcion.php?fun=realloc) y free. (http://c.conclase.net/li
brerias/funcion.php?fun=free)
Punteros y Memoria (http://cslibrary.stanford.edu/) Introducción a los punteros - Biblioteca de
Educación de las Ciencias de la Computación de Stanford
0pointer.de (http://0pointer.de/) Una lista concisa de los códigos de longitud mínima que
referencian a un puntero nulo en diversos lenguajes de programación diferentes.
Memoria dinámica en C++: Operadores new y delete. (http://c.conclase.net/curso/index.ph
p?cap=013b)
"The C book" – containing pointer examples in ANSI C (http://publications.gbdirect.co.uk/c_
book/chapter5/pointers.html)
Joint Technical Committee ISO/IEC JTC 1, Subcommittee SC 22, Working Group WG 14 (8
de setiembre de 2007). International Standard ISO/IEC 9899 (http://www.open-std.org/jtc1/sc
22/WG14/www/docs/n1256.pdf) (PDF) (en inglés). Committee Draft.

Obtenido de «https://es.wikipedia.org/w/index.php?title=Puntero_(informática)&oldid=139946062»

Esta página se editó por última vez el 25 nov 2021 a las 05:22.

El texto está disponible bajo la Licencia Creative Commons Atribución Compartir Igual 3.0;
pueden aplicarse
cláusulas adicionales. Al usar este sitio, usted acepta nuestros términos de uso y nuestra política de privacidad.
Wikipedia® es una marca registrada de la Fundación Wikimedia, Inc., una organización sin ánimo de lucro.

También podría gustarte