Por favor, inclua um exemplo com a explicação.
c++
c
pointers
dereference
asir
fonte
fonte
int *p;
definiria um ponteiro para um número inteiro e*p
desdiferenciaria esse ponteiro, o que significa que ele realmente recuperaria os dados para os quais p aponta.Respostas:
Revendo a terminologia básica
É geralmente bom o suficiente - a menos que você está programando montagem - prever um ponteiro contém um endereço de memória numérica, com 1 referente ao segundo byte na memória do processo, 2 o terceiro, 3 a quarta e assim por diante ....
Quando você deseja acessar os dados / valor na memória para a qual o ponteiro aponta - o conteúdo do endereço com esse índice numérico -, desrefere o ponteiro.
Linguagens de computador diferentes têm notações diferentes para dizer ao compilador ou intérprete que você agora está interessado no valor (atual) do objeto apontado - eu me concentro abaixo em C e C ++.
Um cenário de ponteiro
Considere em C, dado um ponteiro como
p
abaixo ...... quatro bytes com os valores numéricos usados para codificar as letras 'a', 'b', 'c' e um byte 0 para indicar o final dos dados textuais, são armazenados em algum lugar na memória e o endereço numérico desse os dados são armazenados em
p
. Dessa forma, C codifica texto na memória é conhecido como ASCIIZ .Por exemplo, se a literal da string estivesse no endereço 0x1000 e
p
um ponteiro de 32 bits em 0x2000, o conteúdo da memória seria:Note-se que não há uma variável nome / identificador para o endereço 0x1000, mas podemos indiretamente consulte a string literal usando um ponteiro armazenar o endereço:
p
.Desreferenciando o ponteiro
Para nos referir aos caracteres
p
aos quais apontamos, fazemos a desreferênciap
usando uma dessas notações (novamente, para C):Você também pode mover os ponteiros pelos dados apontados, desmarcando-os à medida que avança:
Se você tiver alguns dados que podem ser gravados, poderá fazer coisas como estas:
Acima, você deve saber em tempo de compilação que precisaria de uma variável chamada
x
, e o código solicita ao compilador que organize onde deve ser armazenado, garantindo que o endereço esteja disponível via&x
.Desreferenciando e Acessando um Membro de Dados da Estrutura
Em C, se você tiver uma variável que é um ponteiro para uma estrutura com membros de dados, poderá acessar esses membros usando o
->
operador de desreferenciação:Tipos de dados de vários bytes
Para usar um ponteiro, um programa de computador também precisa de algumas dicas sobre o tipo de dados que está sendo apontado - se esse tipo de dado precisar de mais de um byte para representar, o ponteiro normalmente apontará para o byte de número mais baixo dos dados.
Então, analisando um exemplo um pouco mais complexo:
Ponteiros para memória alocada dinamicamente
Às vezes, você não sabe quanta memória precisará até que seu programa esteja em execução e veja quais dados são lançados nele ... então você pode alocar dinamicamente a memória usando
malloc
. É prática comum armazenar o endereço em um ponteiro ...Em C ++, a alocação de memória é normalmente feita com o
new
operador e a desalocação comdelete
:Veja também ponteiros inteligentes em C ++ abaixo.
Perder e vazar endereços
Freqüentemente, um ponteiro pode ser a única indicação de onde existem alguns dados ou buffer na memória. Se for necessário o uso contínuo desses dados / buffer, ou a capacidade de chamar
free()
oudelete
evitar vazamento de memória, o programador deverá operar em uma cópia do ponteiro ...... ou orquestrar cuidadosamente a reversão de quaisquer alterações ...
Ponteiros inteligentes em C ++
No C ++, é uma prática recomendada usar objetos de ponteiro inteligente para armazenar e gerenciar os ponteiros, desalocando-os automaticamente quando os destruidores dos ponteiros inteligentes são executados. Desde o C ++ 11, a Biblioteca Padrão fornece dois,
unique_ptr
para quando houver um único proprietário para um objeto alocado ...... e
shared_ptr
pela propriedade das ações (usando a contagem de referência ) ...Ponteiros nulos
Em C
NULL
e0
- e adicionalmente em C ++nullptr
- pode ser usado para indicar que um ponteiro não contém atualmente o endereço de memória de uma variável e não deve ser desreferenciado ou usado na aritmética de ponteiros. Por exemplo:Em C e C ++, assim como os tipos numéricos incorporados não necessariamente são padronizados para
0
, nembools
parafalse
, nem sempre os ponteiros são definidos comoNULL
. Tudo isso é definido como 0 / false / NULL quando sãostatic
variáveis ou (apenas C ++) variáveis de membro diretas ou indiretas de objetos estáticos ou suas bases, ou sofrem inicialização zero (por exemplo,new T();
enew T(x, y, z);
executam inicialização zero nos membros de T, incluindo ponteiros, enquantonew T;
não).Além disso, quando você atribuir
0
,NULL
enullptr
para um ponteiro os bits no ponteiro não são necessariamente todos de reset: o ponteiro não pode conter "0" ao nível do hardware, ou consulte o endereço 0 no seu espaço de endereço virtual. O compilador é permitido para armazenar outra coisa lá se tiver motivos para, mas o que ele faz - se você vir e comparar o ponteiro para0
,NULL
,nullptr
ou outro ponteiro que foi atribuído qualquer um desses, o trabalho de comparação obrigação como esperado. Portanto, abaixo do código-fonte no nível do compilador, "NULL" é potencialmente um pouco "mágico" nas linguagens C e C ++ ...Mais sobre endereços de memória e por que você provavelmente não precisa saber
Mais estritamente, os ponteiros inicializados armazenam um padrão de bits que identifica um
NULL
ou um endereço de memória (geralmente virtual ).O caso simples é onde esse é um deslocamento numérico em todo o espaço de endereço virtual do processo; em casos mais complexos, o ponteiro pode ser relativo a alguma área específica da memória, que a CPU pode selecionar com base nos registros de "segmento" da CPU ou em algum tipo de ID de segmento codificado no padrão de bits e / ou procurando em lugares diferentes, dependendo do instruções de código de máquina usando o endereço.
Por exemplo, uma
int*
inicialização adequada para apontar para umaint
variável pode - após converter parafloat*
- a memória de acesso na memória "GPU" bastante distinta da memória em que aint
variável está; depois, uma vez convertida e usada como ponteiro de função, ela pode apontar para opcodes de máquina de retenção de memória distintos para o programa (com o valor numérico doint*
efetivamente um ponteiro aleatório e inválido nessas outras regiões de memória).Linguagens de programação 3GL como C e C ++ tendem a esconder essa complexidade, de modo que:
Se o compilador fornecer um ponteiro para uma variável ou função, você pode desdiferenciá-lo livremente (desde que a variável não seja destruída / desalocada) e é problema do compilador se, por exemplo, um determinado registro de segmento de CPU precisa ser restaurado antes, ou um instrução de código de máquina distinta usada
Se você obtiver um ponteiro para um elemento em uma matriz, poderá usar a aritmética do ponteiro para mover-se para qualquer outro lugar na matriz, ou mesmo para formar um endereço que seja legal para comparar com outros ponteiros para elementos na matriz (ou que foram movidos de maneira semelhante pela aritmética do ponteiro para o mesmo valor de um passado-o-final); novamente em C e C ++, cabe ao compilador garantir que isso "funcione"
Funções específicas do SO, por exemplo, mapeamento de memória compartilhada, podem fornecer ponteiros e eles "simplesmente funcionam" dentro do intervalo de endereços que faz sentido para eles
As tentativas de mover ponteiros legais além desses limites, ou converter números arbitrários em ponteiros ou usar ponteiros convertidos para tipos não relacionados, geralmente têm um comportamento indefinido , portanto devem ser evitados em bibliotecas e aplicativos de nível superior, mas codificam para sistemas operacionais, drivers de dispositivo, etc. talvez precise confiar em comportamentos deixados indefinidos pelo padrão C ou C ++, que, no entanto, são bem definidos por sua implementação ou hardware específico.
fonte
p[1]
e*(p + 1)
idêntico ? Ou seja, gerap[1]
e*(p + 1)
gera as mesmas instruções?p
é apenas 2000: se você tivesse outro ponteirop
, teria que armazenar 2000 em seus quatro ou oito bytes. Espero que ajude! Felicidades.u
contiver uma matrizarr
, o gcc e o clang reconhecerão que o lvalueu.arr[i]
pode acessar o mesmo armazenamento que outros membros da união, mas não reconhecerão que o lvalue*(u.arr+i)
pode fazê-lo. Não tenho certeza se os autores desses compiladores pensam que o último chama UB, ou que o primeiro chama UB, mas eles devem processá-lo de qualquer maneira, mas eles claramente veem as duas expressões como diferentes.Desreferenciar um ponteiro significa obter o valor armazenado no local da memória apontado pelo ponteiro. O operador * é usado para fazer isso e é chamado de operador de desreferenciação.
fonte
[]
também desreferencia um ponteiro (a[b]
está definido para significar*(a + b)
).Um ponteiro é uma "referência" a um valor .. bem como um número de chamada de biblioteca é uma referência a um livro. "Desreferenciando" o número de chamada está passando e recuperando fisicamente esse livro.
Se o livro não estiver lá, o bibliotecário começa a gritar, fecha a biblioteca e duas pessoas estão prontas para investigar a causa de uma pessoa encontrar um livro que não está lá.
fonte
Em palavras simples, desreferenciar significa acessar o valor de um determinado local de memória contra o qual esse ponteiro está apontando.
fonte
Código e explicação do básico do ponteiro :
fonte
Acho que todas as respostas anteriores estão erradas, pois afirmam que a desreferenciação significa acessar o valor real. A Wikipedia fornece a definição correta: https://en.wikipedia.org/wiki/Dereference_operator
Dito isso, podemos desreferenciar o ponteiro sem acessar o valor que ele aponta. Por exemplo:
Desreferenciamos o ponteiro NULL sem acessar seu valor. Ou poderíamos fazer:
Novamente, desreferenciando, mas nunca acessando o valor. Esse código NÃO trava: a trava acontece quando você realmente acessa os dados por um ponteiro inválido. No entanto, infelizmente, de acordo com o padrão, desreferenciar um ponteiro inválido é um comportamento indefinido (com algumas exceções), mesmo que você não tente tocar nos dados reais.
Então, resumindo: desreferenciar o ponteiro significa aplicar o operador de desreferência. Esse operador apenas retorna um valor l para seu uso futuro.
fonte
*p;
causa comportamento indefinido. Embora você está certo de que dereferencing não acessa o valor per se , o código*p;
faz o acesso ao valor.