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 almacenado en otra parte de la memoria del ordenador utilizando su dirección. Un puntero se refiere a una ubicación en memoria, y a la obtención del valor almacenado en esa ubicación se la conoce como desreferenciación del puntero. A modo de analogía, un número de página en el índice de un libro podría considerarse un puntero a la página correspondiente; desreferenciar un puntero sería como ir a la página con el número de página especificada en el índice.

thumb|Puntero 'a' apuntando a la dirección de memoria asociada con la variable 'b'. Obsérvese que en este diagrama en particular, la arquitectura de cálculo utiliza el mismo espacio de direcciones y datos primitivos tanto para punteros como para no punteros; esto no tiene por qué ser el caso.

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 desreferenciar 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.

Un puntero es una implementación más concreta y simple del tipo de datos de referencia más abstracto. Varios lenguajes soportan algún tipo de puntero, aunque algunos tengan más restricciones en su uso que otros. Mientras que se utilice un "puntero" para referirse a referencias en general, se aplica más propiamente a las estructuras de datos cuya interfaz permita explícitamente que el puntero sea manipulado (aritméticamente vía aritmética de punteros) como una dirección de memoria, en oposición a una cookie u opción dónde esto no sea posible. 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 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).

Historia Se le atribuye a Harold Lawson la invención del puntero en 1964.Milestones in Computer Science and Information Technology 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". 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.