Dúvida sobre manipulação de ponteiros (Simples)

Oi, eu estava brincando com ponteiros num arquivo.c quando eu tive a dúvida presente no código a seguir:

    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {
    int a;
    int *p;
    int *b;
    int *c;
    p = &a;
    *p = 2;
    /*Alterando a indiretamente com p*/
    printf(" %d ", a);
    /*alterando a com 3 ponteiros*/
    b = p;
    c = b;
    *c = 10;
        printf("\n\n");
    printf(" %d ", a);
    return 0;
    }

Então, na minha dúvida é no ponteiro *c = 10, como pode ser visto eu criei uma interdepência entre os 3 ponteiros e a variável ‘a’, só que no momento em que eu digito *c = 10, de acordo com as diretrizes da linguagem, estou alterando o conteúdo do endereço que c aponta, o endereço que c aponta é de b, que por sua vez guarda o endereço de a(p = &a, b = p). No meu entedimento b não irá mais guardar o endereço de a e sim 10, porém de algum jeito ele continua guardando o endereço de a, e o valor 10 chega até lá.

Imagine que escrevo o endereço de uma casa em 3 pedaços de papel diferentes. Ou seja, todos apontam pro mesmo terreno. Aí a casa é demolida e fazem um prédio no lugar. O endereço que está nos papéis não mudou, somente o que está no terreno. p, b e c são os pedaços de papel, a é o “terreno” e 2 e 10 são o conteúdo antes e depois (a casa e o prédio)

Perfeito, é exatamente isso que acontece e, no seu caso, c está apontando para o endereço de a, logo, é esperado que o valor de a passe a ser 10.

Errado. O endereço para o qual c aponta é o endereço apontado por b, que é o endereço de a.

Para c apontar para o endereço de b, seu tipo deveria ser int** e não int*. Por exemplo:

int a = 10;
int* b = &a;
int** c = &b;

Esta errado, pois depois que vc atribui o valor de p (que é o endereço de a) à b, vc nunca mais alterou o valor de b, que continua sendo o endereço de a até o fim do programa.

Tentando ser um pouco mais didático…

Toda variável é alocada em algum lugar da memória. Então ao fazer uma declaração como int a, é reservado um espaço para variável a. E toda região da memória possui um endereço (geralmente um número gigante, tipo 0x7ffe39dc53ac, mas neste exemplo, para simplificar, vamos usar números menores).

Então primeiro temos int a, que declara a variável a, aloca um espaço da memória para ela (vamos supor que seja o endereço de memória 42), mas não coloca nenhum valor ainda. Então temos:

variável endereço valor
a 42

Depois o programa declara int *p (um ponteiro para int). Ponteiros são endereços de memória, mas é importante lembrar que, por serem variáveis, eles também estão em algum lugar da memória (afinal, ele precisa de um lugar para armazenar o endereço). Então vamos supor que p foi alocado no endereço 50:

variável endereço valor
a 42
p 50

Não confundir o endereço em que p está alocado com o endereço que ele contém (o valor dele). Se ficou confuso, continue lendo, que isso será esclarecido :slight_smile:

Enfim, depois declaramos mais dois ponteiros: int *b e int *c. Vamos supor que eles foram alocados nos endereços 60 e 70:

variável endereço valor
a 42
p 50
b 60
c 70

Como nenhuma variável teve um valor atribuído, então elas estão sem valor (daí o traço).


Agora que começa a parte interessante. Ao fazer p = &a;, estamos dizendo que o valor do ponteiro p será o endereço da variável a (pois é isso que o operador & faz, pega o endereço de algo). Ou seja:

variável endereço valor
a 42
p 50 42
b 60
c 70

Repare que o valor de p é 42, que é o endereço no qual a está. Dizemos então que “p aponta para a” (ou “p é um ponteiro para a”, ou “p tem o endereço de a”, etc).

E como já dito antes, não confundir o endereço no qual p está alocado (onde ele está na memória, no caso, o endereço 50) com o endereço que ele contém (o valor do ponteiro, o endereço para o qual ele aponta, no caso, 42).


Na linha seguinte temos *p = 2;. O operador * serve para “desreferenciar” (nem sei se essa palavra existe) um ponteiro. Portanto esta linha está dizendo: “Pegue o valor 2 e coloque no endereço para o qual p está apontando”. Eu não estou mudando o endereço para o qual p aponta (ele vai continuar apontando para o endereço 42). O que estou mudando é o valor que está no endereço 42. Ou seja, depois desta linha ficará assim:

variável endereço valor
a 42 2
p 50 42
b 60
c 70

Por isso que na linha seguinte, ao imprimir o valor de a, é mostrado 2.


Depois temos b = p;. Aqui é uma atribuição de ponteiros, que na prática faz com que ambos apontem para o mesmo endereço. O que ele faz basicamente é “pegue o endereço para o qual p aponta, e faça b apontar para ele também”. E como p está apontando para o endereço 42, então depois desta linha, b também estará:

variável endereço valor
a 42 2
p 50 42
b 60 42
c 70

O mesmo vale para a linha seguinte: c = b;. Ela diz para pegar o endereço para o qual b está apontando (no caso, 42) e fazer com que c também aponte para ele:

variável endereço valor
a 42 2
p 50 42
b 60 42
c 70 42

E por fim, temos *c = 10;, que usa o operador de desreferência. Ele diz para pegar o valor 10 e colocar no endereço para o qual c aponta (no caso, é o endereço 42). Então depois desta linha, fica assim:

variável endereço valor
a 42 10
p 50 42
b 60 42
c 70 42

E por isso que ao imprimir a, agora mostra 10.

Sim, compreendi, estava na prática fazendo todos apontarem para a, então obviamente atribuir qualquer valor à qualquer um dos ponteiros com ‘*’ interfereria em a. Muito obrigado pelo tempo dedicado, com explicações bem claras e completas.