Vários ponteiros podem fazer referência à mesma variável em C?

6

É uma peculiaridade de C que muitas vezes confunde os iniciantes, mas parece mágica quando clica: você pode ter uma dúzia de ponteiros, todos olhando para o mesmo endereço de memória.

Considere este cenário. Você declara um número inteiro i. Então você declara três ponteiros p, q e r. Você atribui todos eles ao endereço i.

Veja a última linha. r não precisa saber sobre i diretamente. Ele apenas aponta para o que quer que p esteja apontando. E p está apontando para i. Então r também está apontando para i.

O operador de atribuição aqui copia o endereço, não o valor. Quando você faz r = p, você não está copiando o número inteiro dentro de i. Você está copiando o local da memória que p contém.

Depois que esse código for executado, i terá essencialmente quatro nomes. Você pode acessá-lo via i. Você pode acessá-lo via *p. Você pode acessá-lo via *q. Ou você pode acessá-lo via *r.

Não há limite técnico para quantos ponteiros você pode empilhar dessa forma.

Por que isso é importante

Esta não é apenas sintaxe acadêmica. Isso muda a forma como você pensa sobre o fluxo de dados.

Em linguagens com referências estritas a objetos, copiar um objeto geralmente cria uma nova instância na memória. Em C, copiar um ponteiro é barato. É apenas um endereço de memória. Rápido. Pequeno.

Isso permite que várias partes do seu código manipulem os mesmos dados sem duplicação. Alterar *p e *q vê a alteração imediatamente.

Você está criando aliases para memória.

O risco do alias

É aqui que o “aspecto legal” se torna um risco.

Se p, q e r apontam para i, qualquer um deles pode modificar i.

Agora i é 10. *q é 10. *r é 10.

Mas e se você esquecer que r também está observando i? Você pode presumir que i é estável porque não o tocou diretamente. Você tocou apenas em *q.

É um recurso compartilhado. E os recursos compartilhados são onde residem as condições de corrida e as substituições inesperadas.

Como prevenir efeitos colaterais indesejados

Se você quiser garantir que um ponteiro não substitua acidentalmente os dados destinados a outro, use const.

Agora r pode ser lido i. Pode apontar para isso. Não pode mudar isso.

É assim que você impõe limites em uma linguagem que confia em você para gerenciar a memória manualmente.

Onde isso se encaixa na programação de sistemas

Você vê esse padrão em todo o código do sistema.

As estruturas do kernel geralmente possuem vários ponteiros para o mesmo bloco de controle. Os drivers de dispositivo mapeiam o mesmo registro de hardware para nomes lógicos diferentes.

Entender que os ponteiros são apenas rótulos para endereços ajuda a depurar esses problemas. Quando a memória for corrompida, rastreie os ponteiros. Quem mais