Puntero (programación de computadoras)
AdaEdit
Ada es un lenguaje fuertemente tipado donde todos los punteros están escritos y solo se permiten conversiones de tipo seguro. Todos los punteros se inicializan de forma predeterminada en null
, y cualquier intento de acceder a los datos a través de un puntero null
provoca que se genere una excepción. Los punteros en Ada se denominan tipos de acceso. Ada 83 no permitía la aritmética en los tipos de acceso (aunque muchos proveedores de compiladores la proporcionaron como una característica no estándar), pero Ada 95 admite aritmética «segura» en los tipos de acceso a través del paquete System.Storage_Elements
.
BASICEdit
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 los que tienen los tipos de puntero.
Los dialectos más nuevos de BASIC, como FreeBASIC o BlitzMax, tienen implementaciones de puntero exhaustivas, sin embargo. En FreeBASIC, la aritmética en ANY
punteros ( equivalente a C «s void*
) se tratan como si el puntero ANY
tuviera un ancho de byte. Los punteros ANY
no se pueden desreferenciar, como en C. Además, la conversión entre punteros ANY
y cualquier otro tipo no generará ninguna advertencia.
dim as integer f = 257dim as any ptr g = @fdim as integer ptr i = gassert(*i = 257)assert( (g + 4) = (@f + 1) )
Edición de C y C ++
En C y C ++, los punteros son variables que almacenan direcciones y puede ser nulo. Cada puntero tiene un tipo al que apunta, pero uno puede lanzar libremente entre tipos de puntero (pero no entre un puntero de función y un puntero de objeto). Un tipo de puntero especial llamado «puntero void» permite apuntar a cualquier tipo (no -función) objeto, pero está limitado por el hecho de que no se puede desreferenciar directamente (se convertirá). La dirección en sí a menudo se puede manipular directamente lanzando un puntero hacia y desde un tipo integral de tamaño suficiente, aunque los resultados están definidos por la implementación y pueden causar un comportamiento indefinido; mientras que los estándares C anteriores no tenían un tipo integral que se garantizara que fuera lo suficientemente grande, C99 especifica el uintptr_t
nombre de typedef definido en <stdint.h>
, pero no es necesario que una implementación lo proporcione.
C ++ es totalmente compatible con punteros C y encasillado en C. También es compatible con un nuevo grupo de operadores de encasillamiento para ayudar a detectar algunos lanzamientos peligrosos no deseados en tiempo de compilación. Desde C ++ 11, la biblioteca estándar de C ++ también proporciona punteros inteligentes (unique_ptr
, shared_ptr
y weak_ptr
) que se puede usar en algunas situaciones como una alternativa más segura a los punteros C primitivos. C ++ también admite otra forma de referencia, bastante diferente de un puntero, llamado simplemente referencia o tipo de referencia.
Aritmética de puntero, es decir, la capacidad de modificar la dirección de destino de un puntero con operaciones aritméticas (como así como comparaciones de magnitud), está restringido por el estándar de lenguaje para permanecer dentro de los límites de un único objeto de matriz (o justo después de él), y de lo contrario invocará un comportamiento indefinido. Sumar o restar de un puntero lo mueve por un múltiplo del tamaño de su tipo de datos. Por ejemplo, agregar 1 a un puntero a valores enteros de 4 bytes incrementará la dirección de byte apuntada del puntero en 4. Esto tiene el efecto de incrementar el puntero para que apunte al siguiente elemento en un matriz de números enteros, que suele ser el resultado deseado. La aritmética de punteros no se puede realizar en punteros void
porque el tipo void no tiene tamaño y, por lo tanto, no se puede agregar la dirección apuntada, aunque gcc y otros compiladores realizarán operaciones aritméticas de bytes en void*
como una extensión no estándar, tratándola como si fuera char *
.
La aritmética de punteros proporciona al programador una forma única de tratar con diferentes tipos: sumando y restando el número de elementos requeridos en lugar del desplazamiento real en bytes. (La aritmética de punteros con punteros char *
usa desplazamientos de bytes, porque sizeof(char)
es 1 por definición). En particular, la definición de C declara explícitamente que el la sintaxis a
, que es el n
-ésimo elemento de la matriz a
, es equivalente a *(a + n)
, que es el contenido del elemento señalado por a + n
. Esto implica que n
es equivalente a a
, y se puede escribir, por ejemplo, a
o 3
igualmente bien para acceder al cuarto elemento de una matriz a
.
Si bien es potente, la aritmética de punteros puede ser una fuente de errores informáticos. Tiende a confundir a los programadores novatos, forzándolos a diferentes contextos: una expresión puede ser una aritmética ordinaria o una aritmética de puntero, y algunas veces es fácil confundir una con la otra. En respuesta a esto, muchos lenguajes informáticos modernos de alto nivel (por ejemplo, Java) no permiten el acceso directo a la memoria mediante direcciones. Además, el dialecto C seguro Cyclone aborda muchos de los problemas con los punteros. Consulte el lenguaje de programación C para obtener más información.
El puntero void
, o void*
, es compatible con ANSI C y C ++ como tipo de puntero genérico. Un puntero a void
puede almacenar la dirección de cualquier objeto (no una función) y, en C, se convierte implícitamente a cualquier otro tipo de puntero de objeto en la asignación, pero debe convertirse explícitamente if dereferenced.K & RC usó char*
para el propósito de «puntero independiente de tipo» (antes de ANSI C).
C ++ no permite la conversión implícita de void*
a otros tipos de punteros, incluso en asignaciones. Esta fue una decisión de diseño para evitar conversiones descuidadas e incluso involuntarias, aunque la mayoría de los compiladores solo generan advertencias , no errores, cuando se encuentran con otras conversiones.
En C ++, no hay void&
(referencia a void) para complementar void*
(puntero a void), porque las referencias se comportan como alias a las variables a las que apuntan, y nunca puede haber una variable cuyo tipo sea void
.
Descripción general de la sintaxis de declaración de punteroEditar
Estas declaraciones de puntero c sobre la mayoría de las variantes de declaraciones de puntero. Por supuesto, es posible tener punteros triples, pero los principios fundamentales detrás de un puntero triple ya existen en un puntero doble.
Los () y tienen una prioridad mayor que *.
Edición de C #
En el lenguaje de programación C #, los punteros solo se admiten bajo ciertas condiciones: cualquier bloque de código, incluidos los punteros, debe estar marcado con la palabra clave unsafe
. Estos bloques generalmente requieren permisos de seguridad más altos para poder ejecutarse. La sintaxis es esencialmente la misma que en C ++, y la dirección apuntada puede ser memoria administrada o no administrada. Sin embargo, los punteros a la memoria administrada (cualquier puntero a un objeto administrado) deben declararse con la palabra clave fixed
, que evita que el recolector de basura mueva el objeto señalado como parte de la administración de la memoria mientras el puntero está dentro del alcance, por lo que mantiene la dirección del puntero válida.
Una excepción a esto es el uso de la estructura IntPtr
, que es un equivalente administrado de forma segura a int*
, y no requiere código inseguro. Este tipo se devuelve a menudo cuando se utilizan métodos de System.Runtime.InteropServices
, por ejemplo:
El marco .NET incluye muchas clases y métodos en System
y System.Runtime.InteropServices
espacios de nombres (como la clase Marshal
) que convierten tipos .NET (por ejemplo, System.String
) hacia y desde muchos tipos y punteros no administrados (por ejemplo, LPWSTR
o void*
) para permitir comunicación con código no administrado. La mayoría de estos métodos tienen los mismos requisitos de permisos de seguridad que el código no administrado, ya que pueden afectar lugares arbitrarios en la memoria.
COBOLEdit
El lenguaje de programación COBOL admite punteros a variables. Los objetos de datos primitivos o de grupo (registro) declarados dentro de LINKAGE SECTION
de un programa están intrínsecamente basados en punteros, donde la única memoria asignada dentro del programa es espacio para la dirección del elemento de datos ( normalmente una sola palabra de memoria). En el código fuente del programa, estos elementos de datos se utilizan como cualquier otra WORKING-STORAGE
variable, pero se accede a sus contenidos de forma implícita indirectamente a través de sus LINKAGE
.
El espacio de memoria para cada objeto de datos apuntado generalmente se asigna dinámicamente usando declaraciones externas CALL
o mediante construcciones de lenguaje extendido incrustadas como EXEC CICS
o EXEC SQL
declaraciones.
Las versiones extendidas de COBOL también proporcionan variables de puntero declaradas con USAGE
IS
POINTER
cláusulas. Los valores de dichas variables de puntero se establecen y modifican mediante declaraciones SET
y SET
ADDRESS
.
Algunas versiones extendidas de COBOL también proporcionan PROCEDURE-POINTER
variables, que son capaces de almacenar las direcciones de código ejecutable.
PL / IEdit
El lenguaje PL / I proporciona soporte completo para punteros a todos los tipos de datos (incluidos punteros a estructuras), recursividad, multitarea, manejo de cadenas y amplias funciones integradas.PL / I fue un gran avance en comparación con los lenguajes de programación de su época. Los punteros PL / I no están tipificados y, por lo tanto, no se requiere conversión para desreferenciar o asignar punteros. La sintaxis de declaración para un puntero es DECLARE xxx POINTER;
, que declara un puntero llamado «xxx». Los punteros se utilizan con BASED
variables. Una variable basada se puede declarar con un localizador predeterminado (DECLARE xxx BASED(ppp);
o sin (DECLARE xxx BASED;
), donde xxx es una variable basada, que puede ser una variable de elemento, una estructura o una matriz, y ppp es el puntero predeterminado). Dicha variable puede ser una dirección sin una referencia de puntero explícita (xxx=1;
, o puede direccionarse con una referencia explícita al localizador predeterminado (ppp), o a cualquier otro puntero (qqq->xxx=1;
).
La aritmética de punteros no es parte del estándar PL / I, pero muchos compiladores permiten expresiones de la forma ptr = ptr±expression
. IBM PL / I también tiene la función incorporada PTRADD
para realizar la aritmética. La aritmética de puntero siempre se realiza en bytes.
Los compiladores IBM Enterprise PL / I tienen una nueva forma de puntero escrito llamado HANDLE
.
DEdit
El lenguaje de programación D es un derivado de C y C ++ que es totalmente compatible con C punteros y conversión de tipos en C.
EiffelEdit
El lenguaje orientado a objetos de Eiffel emplea semántica de valores y referencias sin aritmética de punteros. Sin embargo, se proporcionan clases de punteros. Ofrecen aritmética de punteros, conversión de tipos, explícita gestión de memoria, int cara con software que no es de Eiffel y otras características.
FortranEdit
Fortran-90 introdujo una capacidad de puntero fuertemente tipado. Los punteros de Fortran contienen más que una simple dirección de memoria. También encapsulan los límites inferior y superior de las dimensiones de la matriz, los pasos (por ejemplo, para admitir secciones de matriz arbitrarias) y otros metadatos. Un operador de asociación, =>
se usa para asociar un POINTER
a una variable que tiene un TARGET
atributo. La instrucción Fortran-90 ALLOCATE
también se puede usar para asociar un puntero a un bloque de memoria. Por ejemplo, el siguiente código podría usarse para definir y crear una estructura de lista enlazada:
Fortran-2003 agrega soporte para punteros de procedimiento. Además, como parte de la función de interoperabilidad de C, Fortran-2003 admite funciones intrínsecas para convertir punteros estilo C en punteros Fortran y viceversa.
GoEdit
Go tiene punteros. Su sintaxis de declaración es equivalente a la de C, pero escrita al revés, terminando con el tipo. A diferencia de C, Go tiene recolección de basura y no permite la aritmética de punteros. Los tipos de referencia, como en C ++, no existen. Algunos tipos integrados, como mapas y canales, están encuadrados (es decir, internamente son punteros a estructuras mutables) y se inicializan mediante la función make
. En un enfoque de la sintaxis unificada entre punteros y no punteros, el operador de flecha (->
) se ha eliminado: el operador de punto en un puntero se refiere al campo o método del objeto desreferenciado . Sin embargo, esto solo funciona con 1 nivel de indirección.
JavaEdit
A diferencia de C, C ++ o Pascal, no existe una representación explícita de punteros en Java. En cambio, las estructuras de datos más complejas como objetos y matrices se implementan utilizando referencias. El lenguaje no proporciona ningún operador explícito de manipulación de puntero. Sin embargo, todavía es posible que el código intente eliminar la referencia a una referencia nula (puntero nulo), lo que da como resultado una excepción en tiempo de ejecución. El espacio ocupado por los objetos de memoria no referenciados se recupera automáticamente mediante la recolección de basura en tiempo de ejecución.
Modula-2Edit
Los punteros se implementan de manera muy similar a Pascal, al igual que VAR
en llamadas a procedimientos. Modula-2 está aún más tipado que Pascal, con menos formas de escapar del sistema de tipos. Algunas de las variantes de Modula-2 (como Modula-3) incluyen la recolección de basura.
OberonEdit
Al igual que con Modula-2, los punteros están disponibles. Todavía hay menos formas de evadir el sistema de tipos, por lo que Oberon y sus variantes siguen siendo más seguros con respecto a los punteros que Modula-2 o sus variantes. Al igual que con Modula-3, la recolección de basura es parte de la especificación del lenguaje.
PascalEdit
A diferencia de muchos lenguajes que cuentan con punteros, ISO Pascal estándar solo permite que los punteros hagan referencia a variables creadas dinámicamente que son anónimos y no les permiten hacer referencia a variables estándar estáticas o locales. No tiene aritmética de punteros. Los punteros también deben 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 carácter no es compatible con un puntero a un número entero).Esto ayuda a eliminar los problemas de seguridad de tipos inherentes a otras implementaciones de punteros, en particular las que se usan para PL / I o C.También elimina algunos riesgos causados por punteros colgantes, pero la capacidad de soltar dinámicamente el espacio referenciado mediante el uso de dispose
procedimiento estándar (que tiene el mismo efecto que la función de biblioteca free
que se encuentra en C) significa que el riesgo de punteros colgantes no se ha eliminado por completo.
Sin embargo, en algunas implementaciones de compiladores Pascal (o derivados) comerciales y de código abierto, como Free Pascal, Turbo Pascal o Object Pascal en Embarcadero Delphi, se permite que un puntero haga referencia a variables estándar estáticas o locales y puede ser emitir de un tipo de puntero a otro. Además, la aritmética de punteros no tiene restricciones: sumar o restar de un puntero lo mueve esa cantidad de bytes en cualquier dirección, pero usando Inc
o Dec
procedimientos estándar con este mueve el puntero según el tamaño del tipo de datos al que se declara apuntar. También se proporciona un puntero sin tipo con el nombre Pointer
, que es compatible con otros tipos de punteros.