Qual é a diferença entre variáveis ​​e ponteiros?

10

Ao ler um artigo descrevendo as diferenças de OO e programação funcional , deparei-me com indicadores de função. Já faz um tempo desde que terminei meu curso de Ciência da Computação (2003) e, portanto, procurei indicadores para refrescar minha memória.

Ponteiros são variáveis ​​que contêm uma referência a um endereço de memória. Eles podem ser considerados para apontar para os dados contidos nesse endereço de memória, se esses dados existirem. Ou, como no caso do artigo, eles podem indicar o ponto de entrada para uma seção do código e podem ser usados ​​para chamar esse código.

Por que isso é diferente de uma variável? Variáveis ​​são nomes simbólicos para endereços de memória e os compiladores substituirão o nome pelo endereço real. Isso significa que as variáveis ​​contêm referências aos locais da memória e podem ser consideradas como apontando para os dados nesse endereço, se esses dados existirem.

Se a diferença está no comportamento (talvez um ponteiro não possa ser reatribuído em tempo de execução ou apenas um nome de variável simbólico possa ser atribuído, e não qualquer outro valor), isso não significa que é apenas uma variável de um tipo específico, o tipo de ponteiro? Da mesma maneira, uma variável declarada como do tipo inteiro é restringida pela compilação para a qual ela pode ser usada.

O que estou perdendo aqui?

NectarSoft
fonte
4
Nada, um ponteiro é efetivamente um tipo cuja interpretação semântica é que o conteúdo da variável é um endereço. Note, é claro, que há dois endereços, há o endereço do ponteiro (ou seja, onde a variável está armazenada) e o endereço que o ponteiro faz referência (os dados reais no endereço da variável). Um ponteiro é um tipo de referência .
JavaScript é necessário

Respostas:

8

Sua pergunta é interessante de várias maneiras, pois requer distinções cuidadosas para vários problemas. Mas sua visão me parece essencialmente correta. Não li sua referência antes de escrever a maior parte desta resposta para evitar influenciar minha resposta.

Primeiro, sua afirmação Variables are symbolic names for memory addressesestá quase correta, mas confunde o conceito e sua implementação usual. Uma variável é na verdade apenas um contêiner que pode conter um valor que pode ser alterado. Geralmente, esse contêiner é implementado em um computador como um monte de espaço na memória, caracterizado por endereço e tamanho, já que as variáveis ​​podem conter objetos que requerem representações com mais ou menos informações.

Mas considerarei principalmente um ponto de vista mais abstrato da semântica das linguagens, independentemente das técnicas de implementação.

Portanto, variáveis ​​são apenas contêineres de um ponto de vista abstrato. Esse contêiner não precisa ter um nome. No entanto, os idiomas geralmente têm variáveis ​​nomeadas pela associação a um identificador, para que os usos da variável possam ser expressos pelo identificador. Uma variável pode realmente ter vários identificadores através de vários mecanismos de alias. Uma variável também pode ser uma subparte de uma variável maior: um exemplo é uma célula de uma variável de matriz, que pode ser nomeada especificando a variável de matriz e o índice da célula, mas também pode ser associada a identificadores por meio de alias.

Estou usando deliberadamente o contêiner de palavras que é um pouco neutro, para evitar invocar outras palavras que podem ser semanticamente carregadas tecnicamente. Na verdade, está próximo do conceito de referência descrito na wilipedia , que geralmente é confundido com um endereço de memória. A palavra ponteiro em si é muitas vezes entendida como um endereço de memória, mas não acho que isso seja significativo ao considerar a maioria das linguagens de alto nível e provavelmente inapropriado no documento de discussão a que você se refere (embora os endereços possam ser usados), pois é inapropriado. referindo-se a uma implementação específica. No entanto, é apropriado para uma linguagem como C, que deveria estar muito mais próxima dos conceitos de implementação e da arquitetura da máquina.

Na verdade, se você examinar variáveis ​​ou valores no nível de implementação, pode haver vários sistemas complexos de indireção, de "indicadores no nível da máquina", mas que são (e devem ser) invisíveis para o usuário, de modo que o ponto de vista abstrato Eu desenvolvo pode ser válido. Para a maioria das linguagens de programação, o usuário não precisa se preocupar, ou mesmo saber, sobre implementação, pois a implementação pode variar muito para um determinado idioma. Isso pode não ser verdade para alguns idiomas, como C, que são intencionalmente próximos da arquitetura da máquina, como um substituto avançado para linguagens assembly que estão quase diretamente relacionadas à codificação binária explícita, mas com um nível muito baixo para uso conveniente na maioria dos casos. situações.

O que o usuário de um idioma deve saber e, às vezes, deve ser ainda menor que isso, são o que são valores e operações associadas, onde podem estar contidos, como podem ser associados a nomes, como o sistema de nomes funciona, como pode tipos de valores sejam definidos, etc.

Portanto, outro conceito importante é identificadores e nomeação. A nomeação de uma entidade (um valor) pode ser feita associando um identificador a um valor (geralmente em uma declaração). Mas um valor também pode ser obtido aplicando operações a outros valores nomeados. Os nomes podem ser reutilizados e existem regras (regras de escopo) para determinar o que está associado a um determinado identificador, de acordo com o contexto de uso. Também existem nomes especiais, chamados literais, para nomear os valores de alguns domínios, como números inteiros (por exemplo, ) ou booleanos (por exemplo, verdadeiro ).612

A associação de um valor imutável a um identificador é geralmente chamada de constante. Os literais são constantes nesse sentido.

"Contêineres de valor" também podem ser considerados valores, e sua associação com um identificador é uma variável no sentido "ingênuo" usual que você está usando. Então você pode dizer que uma variável é uma "constante de contêiner".

Agora você pode se perguntar qual é a diferença entre associar um identificador a um valor (declaração constante) ou atribuir um valor a uma variável, ou seja, armazenar o valor no contêiner definido como uma constante do contêiner. Essencialmente, a declaração pode ser vista como uma operação que define uma notação, que associa um identificador que é uma entidade sintática a algum valor que é uma entidade semântica. A atribuição é uma operação puramente semântica que modifica um estado, ou seja, modifica o valor de um contêiner. Em certo sentido, a declaração é um meta-conceito sem efeito semântico, além de fornecer um mecanismo de nomeação (isto é, sintático) para entidades semânticas.

Na verdade, as atribuições são operações semânticas que ocorrem dinamicamente à medida que o programa é executado, enquanto as declarações têm uma natureza mais sintática e geralmente devem ser interpretadas no texto do programa, independentemente da execução. É por isso que o escopo estático (isto é, o escopo textual) é geralmente a maneira natural de entender o significado dos identificadores.

Depois de tudo isso, posso dizer que um valor de ponteiro é apenas outro nome para um contêiner, e uma variável de ponteiro é uma variável de contêiner, ou seja, um contêiner (constante) que pode conter outro contêiner (com possíveis limitações no jogo contido impostas por alguns sistema de tipos).

Em relação ao código, você declara [pointers] might indicate the entry point to a section of code and can be used to call that code. Na verdade, isso não é bem verdade. Uma seção do código geralmente não faz sentido sozinha (do ponto de vista de alto nível ou implementação). Do ponto de vista de alto nível, o código geralmente contém identificadores, e você deve interpretá-los no contexto estático em que foram declarados. Mas, na verdade, existe uma possível duplicação do mesmo contexto estático, devido essencialmente à recursão, que é um fenômeno dinâmico (tempo de execução), e o código só pode ser executado em uma instância dinâmica apropriada do contexto estático. Isso é um pouco complexo, mas a consequência é que o conceito apropriado é o de um fechamento que associa um pedaço de código e um ambiente em que os identificadores devem ser interpretados. O fechamento é o conceito semântico adequado, ou seja, é um valor semântico adequadamente definível. Então você pode ter constantes de fechamento, variáveis ​​de fechamento,

Uma função é um fechamento, geralmente com alguns parâmetros para definir ou inicializar algumas de suas entidades (constantes e variáveis).

Estou pulando muitas variações nos usos desses mecanismos.

Os fechamentos podem ser usados ​​para definir estruturas de OO em linguagens imperativas ou funcionais. Na verdade, o trabalho inicial no estilo OO (provavelmente antes do nome) foi feito dessa maneira.

O artigo que você mencionou, que eu examinei rapidamente, parece ser interessante, escrito por uma pessoa competente, mas possivelmente não é uma leitura fácil se você não tiver uma experiência significativa com uma variedade de idiomas e seus modelos computacionais subjacentes.

Mas lembre-se: muitas coisas estão nos olhos de quem vê, desde que ele preserve uma visão consistente. Os pontos de vista podem ser diferentes.

Isso responde sua pergunta?

PS: Esta é uma resposta longa. Se você considera uma parte inadequada, seja explícito sobre qual é. Obrigado.

babou
fonte
Eu tive que ler algumas vezes, mas acho que responde à minha pergunta, sim. Embora minhas definições sejam muito centradas na implementação, a idéia de que um ponteiro é um tipo específico de variável parece ser precisa, ou seja, "um valor de ponteiro é apenas outro nome para um contêiner e uma variável de ponteiro é uma variável de contêiner" Onde eu não obtenha a distinção que você faz é entre um ponteiro que contém o endereço de um bloco de código e ser um contêiner que contém um contêiner que contém um fechamento. A distinção entre a de um contexto estático e a de um programa está em execução?
NectarSoft
11
@NectarSoft A distinção é apenas entre o bloco de código e o fechamento. O que estou dizendo é que, por si só, isolado de qualquer contexto, um bloco de código geralmente não significa nada. Se eu lhe disser que " se os romas são maiores que os borogoves, os toves superam ", a frase não significa nada porque você perde o contexto em que todos esses conceitos são definidos. Esse contexto estático geralmente é o texto que contém o fragmento de código. O problema é que esse próprio contexto estático pode ter várias instâncias de tempo de execução e o fragmento de código deve se referir a apenas uma delas.
babou 31/12/14
11
@NectarSoft (continuação) Portanto, o valor de fechamento é a associação do fragmento de código e uma instância dinâmica do contexto estático que dá sentido a esse fragmento. Uma associação do mesmo fragmento de código a uma instância dinâmica diferente do mesmo contexto estático fornece um fechamento diferente. Normalmente, seu código pode usar uma variável pertencente ao contexto, mas será uma variável diferente para cada instância dinâmica do contexto, embora seu nome (definido estaticamente) permaneça o mesmo. Isso esclarece o problema ou devo criar um exemplo na resposta (o formato dos comentários é restrito)?
babou 31/12/14
Esclarece a questão, obrigado, enquanto levanta outras questões nas quais passarei algum tempo para pensar. Por exemplo, se um ponteiro distinto é necessário para cada fechamento, parece que o ponteiro se torna parte do contexto dinâmico e, portanto, pertence ao fechamento! Também me pergunto sobre limites e hierarquia de fechamento, pois cada um desses contextos associados a um bloco de código estático e referenciado por um ponteiro será necessariamente uma variável em um fechamento próprio. Tudo isso é off topic no entanto por isso vou fazer algumas leituras e talvez outra pergunta quando eu ficar preso mais uma vez
NectarSoft
@NectarSoft Na verdade. ao criar um fechamento, você tenta restringir o contexto associado ao código ao necessário para dar um significado adequado a esse código (até algumas restrições práticas para evitar informações de microgerenciamento). Isso pode ser decidido estaticamente.
babou 01/01
2

A diferença é por definição e aplicação, um ponteiro é uma variável especializada para armazenar um endereço de memória de outra variável; em termos OO, talvez se considere que um ponteiro herda seu comportamento de uma classe geral chamada variável.

Ricardo
fonte