¿Cuál es la diferencia entre variables y punteros?

10

Mientras leía un artículo que describía las diferencias en OO y la programación funcional, me encontré con punteros de función. Ha pasado un tiempo desde que completé mi licenciatura en Ciencias de la Computación (2003), así que busqué punteros para refrescar mi memoria.

Los punteros son variables que contienen una referencia a una dirección de memoria. Se puede considerar que apuntan a los datos contenidos en esa dirección de memoria si tales datos existen. O, como en el caso del artículo, pueden indicar el punto de entrada a una sección de código y pueden usarse para llamar a ese código.

¿Por qué es esto diferente de una variable? Las variables son nombres simbólicos para las direcciones de memoria y los compiladores reemplazarán el nombre con la dirección real. Esto significa que las variables contienen referencias a ubicaciones de memoria y se puede considerar que apuntan a los datos en esa dirección si tales datos existen.

Si la diferencia está en el comportamiento (tal vez no se puede reasignar un puntero en tiempo de ejecución, o solo se le puede asignar un nombre de variable simbólico, no cualquier otro valor), ¿eso no significa que es solo una variable de un tipo en particular, el tipo de puntero? De la misma manera, una variable declarada de tipo entero está restringida por la compilación para lo que puede usarse.

¿Que me estoy perdiendo aqui?

NectarSoft
fuente
44
Nada, un puntero es efectivamente un tipo cuya interpretación semántica es que el contenido de la variable es una dirección. Tenga en cuenta, por supuesto, que hay dos direcciones, la dirección del puntero (es decir, dónde se almacena la variable) y la dirección a la que hace referencia el puntero (los datos reales en la dirección de la variable). Un puntero es un tipo de referencia .
Luke Mathieson

Respuestas:

8

Su pregunta es interesante de varias maneras, ya que requiere distinciones cuidadosas para varios temas. Pero su visión me parece esencialmente correcta. No leí su referencia antes de escribir la mayor parte de esta respuesta para evitar sesgar mi respuesta.

Primero, su declaración Variables are symbolic names for memory addresses, es casi correcta, pero confunde el concepto y su implementación habitual. Una variable es en realidad solo un contenedor que puede contener un valor que se puede cambiar. Por lo general, este contenedor se implementa en una computadora como un espacio de memoria, caracterizado por una dirección y un tamaño, ya que las variables pueden contener objetos que requieren representaciones con más o menos información.

Pero consideraré principalmente un punto de vista más abstracto de la semántica de los lenguajes, independientemente de las técnicas de implementación.

Entonces las variables son solo contenedores desde un punto de vista abstracto. Tal contenedor no necesita tener un nombre. Sin embargo, los idiomas a menudo tienen variables que se nombran al asociarle un identificador, de modo que el identificador puede expresar los usos de la variable. Una variable puede tener varios identificadores a través de varios mecanismos de alias. Una variable también puede ser una subparte de una variable más grande: un ejemplo es una celda de una variable de matriz, que puede nombrarse especificando la variable de matriz y el índice de la celda, pero también podría asociarse con identificadores mediante alias.

Estoy usando deliberadamente el contenedor de palabras que es algo neutral, para evitar invocar otras palabras que pueden cargarse semánticamente técnicamente. En realidad, está cerca del concepto de referencia descrito en wilipedia , que a menudo se confunde con una dirección de memoria. La palabra puntero en sí misma a menudo se entiende como una dirección de memoria, pero no creo que sea significativa cuando se consideran la mayoría de los lenguajes de alto nivel, y probablemente sea inapropiada en el documento de discusión al que se refiere (aunque se pueden usar direcciones), ya que es inapropiada refiriéndose a una implementación específica. Sin embargo, es apropiado para un lenguaje como C, que se supone que está mucho más cerca de los conceptos de implementación y la arquitectura de la máquina.

En realidad, si observa las variables o valores a nivel de implementación, puede haber varios sistemas complejos de indirección, de "punteros a nivel de máquina", pero que son (y deberían ser) invisibles para el usuario, de modo que el punto de vista abstracto Yo desarrollo puede ser válido. Para la mayoría de los lenguajes de programación, el usuario no debería tener que preocuparse, ni siquiera saber, acerca de la implementación, ya que la implementación puede variar mucho para un lenguaje determinado. Esto puede no ser cierto para algunos lenguajes, como C, que están intencionalmente cerca de la arquitectura de la máquina, como un sustituto avanzado para lenguajes de ensamblaje que están en relación casi directa con la codificación binaria explícita, pero un nivel demasiado bajo para un uso conveniente en la mayoría situaciones

Lo que el usuario de un idioma debe saber, y a veces debería ser incluso menos que eso, es qué son los valores y las operaciones asociadas, dónde pueden estar contenidos, cómo pueden asociarse a los nombres, cómo funciona el sistema de nombres, cómo puede se definirán tipos de valores, etc.

612

La asociación de un valor invariable con un identificador generalmente se denomina constante. Los literales son constantes en ese sentido.

Los "contenedores de valores" también pueden considerarse como valores, y su asociación con un identificador es una variable en el sentido "ingenuo" habitual que ha estado utilizando. Entonces podría decir que una variable es una "constante de contenedor".

Ahora puede preguntarse cuál es la diferencia entre asociar un identificador con un valor (declaración constante) o asignar un valor a una variable, es decir, almacenar el valor en el contenedor definido como una constante de contenedor. Esencialmente, la declaración puede verse como una operación que define una notación, que asocia un identificador que es una entidad sintáctica a algún valor que es una entidad semántica. La asignación es una operación puramente semántica que modifica un estado, es decir, modifica el valor de un contenedor. En cierto sentido, la declaración es un metaconcepto sin efecto semántico, aparte de proporcionar un mecanismo de nomenclatura (es decir, sintáctico) para las entidades semánticas.

En realidad, las asignaciones son operaciones semánticas que ocurren dinámicamente a medida que se ejecuta el programa, mientras que las declaraciones tienen una naturaleza más sintáctica y generalmente deben interpretarse en el texto del programa, independientemente de la ejecución. Esta es la razón por la cual el alcance estático (es decir, el alcance textual) suele ser la forma natural de comprender el significado de los identificadores.

Después de todo esto, puedo decir que un valor de puntero es solo otro nombre para un contenedor, y una variable de puntero es una variable de contenedor, es decir, un contenedor (constante) que puede contener otro contenedor (con posibles limitaciones en el juego que contiene impuesto por algunos sistema de tipo).

Con respecto al código, usted declara [pointers] might indicate the entry point to a section of code and can be used to call that code. En realidad, esto no es del todo cierto. Una sección de código a menudo no tiene sentido por sí sola (desde el punto de vista de alto nivel o implementación). Desde un punto de vista de alto nivel, el código generalmente contiene identificadores, y usted debe interpretar estos identificadores en el contexto estático donde fueron declarados. Pero en realidad existe una posible duplicación del mismo contexto estático, debido esencialmente a la recursividad, que es un fenómeno dinámico (tiempo de ejecución), y el código solo puede ejecutarse en una instancia dinámica apropiada del contexto estático. Esto es un poco complejo, pero la consecuencia es que el concepto apropiado es el de un cierre que asocia un fragmento de código y un entorno donde se deben interpretar los identificadores. El cierre es el concepto semántico apropiado, es decir, es un valor semántico adecuadamente definible. Entonces puede tener constantes de cierre, variables de cierre,

Una función es un cierre, generalmente con algunos parámetros para definir o inicializar algunas de sus entidades (constantes y variables).

Estoy omitiendo muchas variaciones en los usos de estos mecanismos.

Los cierres se pueden usar para definir estructuras OO en lenguajes imperativos o funcionales. En realidad, los primeros trabajos sobre el estilo OO (probablemente antes del nombre) se hicieron de esa manera.

El documento al que hace referencia, que leí rápidamente, parece ser interesante, escrito por una persona competente, pero posiblemente no sea una lectura fácil si no tiene una experiencia significativa con una variedad de idiomas y sus modelos computacionales subyacentes.

Pero recuerde: hay muchas cosas en los ojos del espectador, siempre que conserve una visión coherente. Los puntos de vista pueden diferir.

¿Responde esto a tu pregunta?

PD: Esta es una respuesta larga. Si considera que alguna parte es inadecuada, sea explícito sobre cuál es. Gracias.

babou
fuente
Tuve que leerlo varias veces, pero creo que responde a mi pregunta, sí. Aunque mis definiciones están demasiado centradas en la implementación, la idea de que un puntero es un tipo particular de variable parece ser precisa, es decir, "un valor de puntero es solo otro nombre para un contenedor, y una variable de puntero es una variable de contenedor" . obtener la distinción que hace es entre un puntero que contiene la dirección de un bloque de código y ser un contenedor que contiene un contenedor que contiene un cierre. ¿Es la distinción entre la de un contexto estático y la de un programa en ejecución?
NectarSoft
1
@NectarSoft La distinción es solo entre bloque de código y cierre. Lo que digo es que, por sí solo, aislado de cualquier contexto, un bloque de código generalmente no significa nada. Si te digo que " si los momentos son más grandes que los borogoves, entonces los gritos de los toves ", la oración no significa nada porque te pierdes el contexto donde se definen todos estos conceptos. Este contexto estático suele ser el texto que encierra el fragmento de código. El problema es que este contexto estático en sí mismo puede tener varias instancias de tiempo de ejecución, y el fragmento de código debe referirse solo a una de ellas.
babou
1
@NectarSoft (continuación) Por lo tanto, el valor de cierre es la asociación del fragmento de código y una instancia dinámica de contexto estático que le da significado a este fragmento. Una asociación del mismo fragmento de código con una instancia dinámica diferente del mismo contexto estático da un cierre diferente. Por lo general, su código puede usar una variable que pertenece al contexto th, pero será una variable diferente para cada instancia dinámica del contexto, aunque su nombre (definido estáticamente) sigue siendo el mismo. ¿Esto aclara el problema, o debería construir un ejemplo en la respuesta (el formato de los comentarios está restringido)?
babou
Aclara el problema, gracias, al tiempo que plantea otras preguntas en las que pasaré algún tiempo para pensar. Por ejemplo, si se requiere un puntero distinto para cada cierre, parece que el puntero se convierte en parte del contexto dinámico y, por lo tanto, pertenece al cierre. También me pregunto acerca de los límites de cierre y la jerarquía de cierre, ya que cada uno de estos contextos asociados con un bloque de código estático y al que hace referencia un puntero será necesariamente una variable en un cierre propio. Sin embargo, todo esto está fuera de tema, por lo que
leeré un
@NectarSoft en realidad. cuando crea un cierre, intenta restringir el contexto asociado al código a lo que es necesario para darle el significado adecuado a ese código (hasta algunas restricciones prácticas para evitar la microgestión de información). Esto se puede decidir estáticamente.
babou 01 de
2

La diferencia es, por definición y aplicación, un puntero es una variable especializada para contener una dirección de memoria de otra variable; en términos OO, se podría considerar que un puntero hereda su comportamiento de una clase general llamada variable.

Ricardo
fuente