Ponteiro (programação de computador)
AdaEdit
Ada é uma linguagem fortemente tipada onde todos os ponteiros são digitados e apenas conversões de tipo seguro são permitidas. Todos os ponteiros são inicializados por padrão em null
, e qualquer tentativa de acessar dados por meio de um ponteiro null
causa o surgimento de uma exceção. Ponteiros em Ada são chamados de tipos de acesso. Ada 83 não permitia aritmética em tipos de acesso (embora muitos fornecedores de compiladores o fornecessem como um recurso não padrão), mas Ada 95 suporta aritmética “segura” em tipos de acesso por meio do pacote System.Storage_Elements
.
BASICEdit
Várias versões antigas do BASIC para a plataforma Windows tinham suporte para STRPTR () para retornar o endereço de uma string e para VARPTR () para retornar o endereço de uma variável. Visual Basic 5 também tinha suporte para OBJPTR () para retornar o endereço de uma interface de objeto e para um operador ADDRESSOF retornar o endereço de uma função. Os tipos de todos eles são inteiros, mas seus valores são equivalentes a aqueles mantidos por tipos de ponteiro.
Dialetos mais recentes do BASIC, como FreeBASIC ou BlitzMax, têm implementações de ponteiro exaustivas, no entanto. No FreeBASIC, aritmética em ponteiros ANY
( equivalente a C “s void*
) são tratados como se o ponteiro ANY
tivesse uma largura de byte. Os ponteiros ANY
não podem ser desreferenciados, como em C. Além disso, a conversão entre ANY
e ponteiros de qualquer outro tipo não gerará nenhum aviso.
dim as integer f = 257dim as any ptr g = @fdim as integer ptr i = gassert(*i = 257)assert( (g + 4) = (@f + 1) )
Edição C e C ++
Em C e C ++ os ponteiros são variáveis que armazenam endereços e pode ser nulo. Cada ponteiro tem um tipo para o qual aponta, mas pode-se lançar livremente entre os tipos de ponteiro (mas não entre um ponteiro de função e um ponteiro de objeto). Um tipo de ponteiro especial denominado “ponteiro void” permite apontar para qualquer (não -função) objeto, mas é limitado pelo fato de que não pode ser desreferenciado diretamente (deve ser lançado). O endereço em si pode frequentemente ser diretamente manipulado lançando um ponteiro de e para um tipo integral de tamanho suficiente, embora os resultados sejam definidos pela implementação e possam, de fato, causar um comportamento indefinido; enquanto os padrões C anteriores não tinham um tipo integral garantido como grande o suficiente, o C99 especifica o uintptr_t
nome do typedef definido em <stdint.h>
, mas uma implementação não precisa fornecê-lo.
C ++ suporta totalmente ponteiros C e conversão de tipos em C. Ele também oferece suporte a um novo grupo de operadores de conversão de tipos para ajudar a capturar algumas conversões perigosas não intencionais em tempo de compilação. Desde C ++ 11, a biblioteca padrão C ++ também fornece ponteiros inteligentes (unique_ptr
, shared_ptr
e weak_ptr
) que pode ser usado em algumas situações como uma alternativa mais segura para ponteiros C primitivos. C ++ também suporta outra forma de referência, bem diferente de um ponteiro, chamada simplesmente de referência ou tipo de referência.
Aritmética de ponteiro, ou seja, a capacidade de modificar o endereço de destino de um ponteiro com operações aritméticas (como bem como comparações de magnitude), é restrito pelo padrão de linguagem para permanecer dentro dos limites de um único objeto de matriz (ou logo depois dele) e, de outra forma, invocará um comportamento indefinido. Adicionar ou subtrair de um ponteiro move-o por um múltiplo do tamanho de seu tipo de dados. Por exemplo, adicionar 1 a um ponteiro para valores inteiros de 4 bytes aumentará o endereço de byte apontado do ponteiro em 4. Isso tem o efeito de incrementar o ponteiro para apontar para o próximo elemento em um contíguo array de inteiros – que geralmente é o resultado pretendido. A aritmética de ponteiro não pode ser executada em ponteiros void
porque o tipo void não tem tamanho e, portanto, o endereço apontado não pode ser adicionado, embora gcc e outros compiladores executem aritmética de bytes em void*
como uma extensão não padrão, tratando-a como se fosse char *
.
A aritmética do ponteiro fornece ao programador um maneira única de lidar com diferentes tipos: somando e subtraindo o número de elementos necessários em vez do deslocamento real em bytes. (Aritmética de ponteiro com char *
ponteiros usa deslocamentos de byte, porque sizeof(char)
é 1 por definição.) Em particular, a definição C declara explicitamente que o sintaxe a
, que é o n
-ésimo elemento da matriz a
, é equivalente para *(a + n)
, que é o conteúdo do elemento apontado por a + n
. Isso implica que n
é equivalente a a
e pode-se escrever, por exemplo, a
ou 3
igualmente bem para acessar o quarto elemento de uma matriz a
.
Embora poderosa, a aritmética de ponteiros pode ser uma fonte de bugs de computador. Isso tende a confundir os programadores novatos, forçando-os a diferentes contextos: uma expressão pode ser aritmética comum ou aritmética de ponteiro, e às vezes é fácil confundir uma com a outra. Em resposta a isso, muitas linguagens de computador modernas de alto nível (por exemplo, Java) não permitem acesso direto à memória usando endereços. Além disso, o dialeto C seguro Cyclone aborda muitos dos problemas com ponteiros. Veja a linguagem de programação C para mais discussão.
O ponteiro void
ou void*
é compatível com ANSI C e C ++ como um tipo de ponteiro genérico. Um ponteiro para void
pode armazenar o endereço de qualquer objeto (não função) e, em C, é convertido implicitamente para qualquer outro tipo de ponteiro de objeto na atribuição, mas deve ser explicitamente convertido if dereferenced.K & RC usado char*
para a finalidade de “ponteiro agnóstico de tipo” (antes de ANSI C).
C ++ não permite a conversão implícita de void*
para outros tipos de ponteiro, mesmo em atribuições. Esta foi uma decisão de design para evitar conversões descuidadas e até mesmo não intencionais, embora a maioria dos compiladores apenas exiba avisos , não erros, ao encontrar outros casts.
Em C ++, não há void&
(referência a void) para complementar void*
(ponteiro para void), porque as referências se comportam como apelidos para as variáveis para as quais apontam e nunca pode haver uma variável cujo tipo seja void
.
Visão geral da sintaxe da declaração de ponteiro
Estas declarações de ponteiro c sobre a maioria das variantes de declarações de ponteiro. Claro que é possível ter ponteiros triplos, mas os princípios básicos por trás de um ponteiro triplo já existem em um ponteiro duplo.
O () e tem uma prioridade maior que *.
C # Edit
Na linguagem de programação C #, os ponteiros são suportados apenas sob certas condições: qualquer bloco de código incluindo ponteiros deve ser marcado com a palavra-chave unsafe
. Esses blocos geralmente requerem permissões de segurança mais altas para serem executados. A sintaxe é essencialmente a mesma que em C ++, e o endereço apontado pode ser de memória gerenciada ou não gerenciada. No entanto, os ponteiros para a memória gerenciada (qualquer ponteiro para um objeto gerenciado) devem ser declarados usando a palavra-chave fixed
, que evita que o coletor de lixo mova o objeto apontado como parte do gerenciamento de memória enquanto o o ponteiro está no escopo, mantendo assim o endereço do ponteiro válido.
Uma exceção a isso é o uso da estrutura IntPtr
, que é um seguro gerenciado equivalente a int*
e não requer código inseguro. Este tipo é frequentemente retornado ao usar métodos de System.Runtime.InteropServices
, por exemplo:
A estrutura .NET inclui muitas classes e métodos no System
e System.Runtime.InteropServices
namespaces (como a classe Marshal
) que convertem tipos .NET (por exemplo, System.String
) para e de muitos tipos e ponteiros não gerenciados (por exemplo, LPWSTR
ou void*
) para permitir comunicação com código não gerenciado. A maioria desses métodos tem os mesmos requisitos de permissão de segurança que o código não gerenciado, uma vez que podem afetar lugares arbitrários na memória.
COBOLEdit
A linguagem de programação COBOL suporta ponteiros para variáveis. Objetos de dados primitivos ou de grupo (registro) declarados dentro do LINKAGE SECTION
de um programa são inerentemente baseados em ponteiros, onde a única memória alocada dentro do programa é o espaço para o endereço do item de dados ( normalmente uma única palavra de memória). No código-fonte do programa, esses itens de dados são usados como qualquer outra WORKING-STORAGE
variável, mas seus conteúdos são acessados indiretamente por meio de seus LINKAGE
ponteiros .
O espaço de memória para cada objeto de dados apontado é normalmente alocado dinamicamente usando instruções CALL
externas ou por meio de construções de linguagem estendida incorporadas, como EXEC CICS
ou EXEC SQL
instruções.
Versões estendidas de COBOL também fornecem variáveis de ponteiro declaradas com USAGE
cláusulas IS
POINTER
. Os valores dessas variáveis de ponteiro são estabelecidos e modificados usando as instruções SET
e SET
ADDRESS
.
Algumas versões estendidas do COBOL também fornecem PROCEDURE-POINTER
variáveis, que são capazes de armazenar os endereços do código executável.
PL / IEdit
A linguagem PL / I fornece suporte completo para ponteiros para todos os tipos de dados (incluindo ponteiros para estruturas), recursão, multitarefa, manipulação de strings e funções integradas extensivas.PL / I foi um grande avanço em comparação com as linguagens de programação de sua época. Os ponteiros PL / I não são digitados e, portanto, nenhuma conversão é necessária para desreferenciação ou atribuição de ponteiro. A sintaxe de declaração de um ponteiro é DECLARE xxx POINTER;
, que declara um ponteiro chamado “xxx”. Ponteiros são usados com variáveis BASED
. Uma variável baseada pode ser declarada com um localizador padrão (DECLARE xxx BASED(ppp);
ou sem (DECLARE xxx BASED;
), onde xxx é uma variável baseada, que pode ser uma variável de elemento, uma estrutura ou um array, e ppp é o ponteiro padrão). Essa variável pode ser endereçada sem uma referência de ponteiro explícita (xxx=1;
, ou pode ser endereçada com uma referência explícita ao localizador padrão (ppp) ou a qualquer outro ponteiro (qqq->xxx=1;
).
A aritmética de ponteiro não faz parte do padrão PL / I, mas muitos compiladores permitem expressões na forma ptr = ptr±expression
. O IBM PL / I também possui a função interna PTRADD
para realizar a aritmética. A aritmética do ponteiro é sempre realizada em bytes.
Os compiladores IBM Enterprise PL / I têm um nova forma de ponteiro digitado chamado de HANDLE
.
DEdit
A linguagem de programação D é um derivado de C e C ++ que suporta totalmente C ponteiros e conversão de tipos C.
EiffelEdit
A linguagem orientada a objetos Eiffel emprega valor e semântica de referência sem aritmética de ponteiro. No entanto, classes de ponteiro são fornecidas. Elas oferecem aritmética de ponteiro, conversão de tipos, explícita gerenciamento de memória, int erface com software não-Eiffel e outros recursos.
FortranEdit
O Fortran-90 introduziu uma capacidade de ponteiro fortemente tipado. Os ponteiros Fortran contêm mais do que apenas um endereço de memória simples. Eles também encapsulam os limites inferior e superior das dimensões da matriz, avanços (por exemplo, para suportar seções arbitrárias da matriz) e outros metadados. Um operador de associação, =>
é usado para associar um POINTER
a uma variável que tem um TARGET
atributo. A instrução Fortran-90 ALLOCATE
também pode ser usada para associar um ponteiro a um bloco de memória. Por exemplo, o código a seguir pode ser usado para definir e criar uma estrutura de lista vinculada:
Fortran-2003 adiciona suporte para ponteiros de procedimento. Além disso, como parte do recurso de interoperabilidade C, o Fortran-2003 suporta funções intrínsecas para converter ponteiros estilo C em ponteiros Fortran e vice-versa.
GoEdit
Go tem ponteiros. Sua sintaxe de declaração é equivalente à de C, mas escrita ao contrário, terminando com o tipo. Ao contrário de C, Go tem coleta de lixo e não permite aritmética de ponteiro. Tipos de referência, como em C ++, não existem. Alguns tipos integrados, como mapas e canais, são encaixotados (ou seja, internamente, eles são ponteiros para estruturas mutáveis) e são inicializados usando a função make
. Em uma abordagem de sintaxe unificada entre ponteiros e não ponteiros, o operador de seta (->
) foi descartado: o operador de ponto em um ponteiro refere-se ao campo ou método do objeto não referenciado . Isso, no entanto, funciona apenas com 1 nível de indireção.
JavaEdit
Ao contrário de C, C ++ ou Pascal, não há representação explícita de ponteiros em Java. Em vez disso, estruturas de dados mais complexas, como objetos e arrays, são implementadas usando referências. A linguagem não fornece nenhum operador de manipulação de ponteiro explícito. Ainda é possível que o código tente cancelar a referência de uma referência nula (ponteiro nulo), no entanto, o que resulta em uma exceção de tempo de execução sendo lançada. O espaço ocupado por objetos de memória não referenciados é recuperado automaticamente pela coleta de lixo em tempo de execução.
Modula-2Edit
Os ponteiros são implementados quase como em Pascal, assim como VAR
em chamadas de procedimento. Modula-2 é ainda mais fortemente tipado do que Pascal, com menos maneiras de escapar do sistema de tipos. Algumas das variantes do Modula-2 (como Modula-3) incluem coleta de lixo.
OberonEdit
Assim como no Modula-2, ponteiros estão disponíveis. Existem ainda menos maneiras de escapar do sistema de tipos e, portanto, Oberon e suas variantes ainda são mais seguros com relação a ponteiros do que Modula-2 ou suas variantes. Tal como acontece com Modula-3, a coleta de lixo é uma parte da especificação da linguagem.
PascalEdit
Ao contrário de muitas linguagens que apresentam ponteiros, o padrão ISO Pascal permite apenas que os ponteiros façam referência a variáveis criadas dinamicamente que são anônimos e não permitem que façam referência a variáveis estáticas ou locais padrão. Não possui aritmética de ponteiro. Os ponteiros também devem ter um tipo associado e um ponteiro para um tipo não é compatível com um ponteiro para outro tipo (por exemplo, um ponteiro para um char não é compatível com um ponteiro para um inteiro).Isso ajuda a eliminar os problemas de segurança de tipo inerentes a outras implementações de ponteiro, particularmente aquelas usadas para PL / I ou C. Também remove alguns riscos causados por ponteiros pendentes, mas a capacidade de liberar dinamicamente o espaço referenciado usando o dispose
procedimento padrão (que tem o mesmo efeito que a função de biblioteca free
encontrada em C) significa que o risco de ponteiros pendurados não foi totalmente eliminado.
No entanto, em algumas implementações de compilador Pascal (ou derivados) comerciais e de código aberto —como Free Pascal, Turbo Pascal ou Object Pascal no Embarcadero Delphi— um ponteiro é permitido para referenciar variáveis estáticas ou locais padrão e pode ser lançar de um tipo de ponteiro para outro. Além disso, a aritmética de ponteiro é irrestrita: adicionar ou subtrair de um ponteiro move-o por esse número de bytes em qualquer direção, mas usando Inc
ou Dec
procedimentos padrão com ele move o ponteiro pelo tamanho do tipo de dados para o qual ele é declarado apontar. Um ponteiro não digitado também é fornecido sob o nome Pointer
, que é compatível com outros tipos de ponteiro.