Jump to content

Ponteiros :(


kodiak
 Share

Recommended Posts

Viva pessoal.

Cheguei agora àquela que para muitos é a parte mais complicada de C. Os ponteiros. Como não poderia deixar de ser, também eu estou com dúvidas.

Par me guiar um pouco, fiz um pequeno código para ir vendo como funcionam os ponteiros e memória.

O código é o seguinte

#include <stdio.h>
#include <stdlib.h>

int main()
{

    int num; /*cria a variável num mas não a inicializa. Fica num local de memoria*/
    printf("num = %d (tem um valor ao calhas) e esta no endereco de memoria em decimal %08d\n\n", num, &num);

    int *pont; /*cria um ponteiro para inteiros mas não aponta para nada. Fica num local de memoria*/
    printf("pont = %d (tem um valor ao calhas) e esta no endereco de memoria em decimal %08d\n\n", pont,&pont);

    /*Se fizer printf("*pont = %d\n",*pont); da erro porque apesar de se ter criado o ponteiro ele não esta a apontar para nada. so na linha abaixo e que e atribuido um endereço de memória para onde o ponteiro aponta*/

    pont = &num; /*pont aponta para num*/
    printf("pont = %d (o valor apontado por pont e o mesmo de num) aponta para o endereco em decimal (o mesmo de num) %08d e esta no endereco de memoria em decimal %08d\n\n", *pont, pont, &pont);

    num = 555;
    printf("Num = %d (tem o valor atribuido na linha anterior) e esta no endereco de memoria em decimal %08d\n\n", num, &num);
    printf("O valor apontado por pont e %d (o mesmo de num 555) e aponta para o mesmo endereco que num %08d\n\n", *pont, pont);

    num = *pont + 111; /*vai ao valor apontado por pont, retira o valor e adiciona 111*/
    printf("Num = %d (tem o valor atribuido na linha anterior 555+111)\n\n", num);

    int **pont2; /*cria um ponteiro para ponteiro de inteiros*/
    printf("pont2 esta no endereco %08d e tem o valor %d\n", &pont2, pont2);
    printf("*pont2 esta no endereco %08d e tem o valor %d\n", &*pont2, *pont2);

    /*Não entendo porque é que fazendo o printf abaixo dá erro*/
    /*printf("**pont2 esta no endereco %08d e tem o valor %d\n\n", &**pont2, **pont2);*/

    pont2 = &pont; /*pont2 aponta para pont o que faz com que aponte indirectamente para num*/
    printf("\nO valor apontado por **pont2 = %d\n", **pont2);
    printf("\nO valor apontado por *pont2 = %08d que e o endereco de num. E assim pq pont2 aponta para pont que por sua vez aponta para num\n", *pont2);
    printf("\nO valor apontado por pont2 = %08d que e o endereco de pont\n", pont2);

    return 0;
}

E fiz o desenho seguinte para me ir orientando:

gODQz.jpg

As minhas perguntas são as seguintes:

1 - Pq é que os printf que eu assinalo não funcionam e dão erro?

2 - A forma como desenhei a tabela é como as coisas efectivamente se passam?

3 - Eu declaro int **pont2. *pont2 e pont2 existem????

4 - Conhecem algum sítio onde possa aprender bem isto? (preferencialmente com desenhos)

Obrigado,

kodaik

Link to comment
Share on other sites

1 - Pq é que os printf que eu assinalo não funcionam e dão erro?

Tu proprio respondes (bem) às tuas perguntas 👍

3 - Eu declaro int **pont2. *pont2 e pont2 existem????

Nao. Repara que pont2 pode variar ao longo do programa (tal como j depois da declaracao int j). Sempre que pont2 muda, obviamente que *pont2 e **pont2 tambem mudam.

4 - Conhecem algum sítio onde possa aprender bem isto? (preferencialmente com desenhos)

Os ponteiros para ponteiros (para ponteiros ...) usam-se mais em programas que necessitam de arrays ou listas. Faz exemplos de programas com arrays e listas (muda os arrays para listas e vice-versa; arrays de arrays, listas de arrays; arrays de listas; listas de listas; ...) que acabas por perceber.

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

Obrigado pmg.

Então quando faço

printf("**pont2 esta no endereco %08d e tem o valor %d\n\n", &**pont2, **pont2);

dá erro porque não inicializei o ponteiro. Apenas funciona depois de fazer pont2 = &pont;.

É isso?

kodiak

Link to comment
Share on other sites

Exacto.

Nota que &**pont2 é o mesmo que *pont2.


Nao sei se ajuda, mas eu gosto de pensar em todas as variaveis (e outros objectos (nao no sentido POO)) como uma caixa. Cada caixa tem uma cor (um tipo) e um valor.

Ao declarares int **pont2; estas a arranjar uma caixa vermelha (de tipo int**).

O conteudo da caixa vermelha é uma ligacao a outra caixa de cor verde (de tipo int*).

Estas caixas de cor verde, por sua vez contem ponteiros (ligacoes) a caixas de cor azul (de tipo int).

int main(void) {
    int azul, *verde, **vermelho;
    /* os conteudos das 3 caixas sao "invalidos" */
    verde = &azul; /* conteudo da caixa "verde" é a ligacao a caixa azul */
    vermelho = &verde;
    **vermelho = 42; /* segue a ligacao da caixa vermelha (para a caixa verde)
                     /* e logo a seguir segue a ligacao da caixa verde (para a caixa azul)
                     /* e mete o valor 42 na caixa azul */
                     /* Nota que 42 e a caixa azul tem o mesmo tipo, nomeadamente int */
    printf("azul tem %d\n", azul);
    return 0;
}

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

Exacto.

Nota que &**pont2 é o mesmo que *pont2.


Nao sei se ajuda, mas eu gosto de pensar em todas as variaveis (e outros objectos (nao no sentido POO)) como uma caixa. Cada caixa tem uma cor (um tipo) e um valor.

Ao declarares int **pont2; estas a arranjar uma caixa vermelha (de tipo int**).

O conteudo da caixa vermelha é uma ligacao a outra caixa de cor verde (de tipo int*).

Estas caixas de cor verde, por sua vez contem ponteiros (ligacoes) a caixas de cor azul (de tipo int).

int main(void) {
    int azul, *verde, **vermelho;
    /* os conteudos das 3 caixas sao "invalidos" */
    verde = &azul; /* conteudo da caixa "verde" é a ligacao a caixa azul */
    vermelho = &verde;
    **vermelho = 42; /* segue a ligacao da caixa vermelha (para a caixa verde)
                     /* e logo a seguir segue a ligacao da caixa verde (para a caixa azul)
                     /* e mete o valor 42 na caixa azul */
                     /* Nota que 42 e a caixa azul tem o mesmo tipo, nomeadamente int */
    printf("azul tem %d\n", azul);
    return 0;
}

Muito BOM. As simple as it gets-

Muito obrigado pmg

Link to comment
Share on other sites

Afinal ainda tenho mais dúvidas.

No código

int num;
int *pont;
int **pont2;

A variável, o ponteiro e o ponteiro para ponteiro são declarados mas não inicializados. Imagino que a cada um seja atribuído um espaço de memória que contêm tralha precisamente por não terem sido inicializados.

Como já referi em posts anteriores, se fizer

 printf("num e inicializado a %8d e esta no endereco de memoria %8d\n", num, &num)

ou

 printf("pont e inicializado a %8d e esta no endereco de memoria %8d\n", *pont, &pont)

funciona.

Mas se tentar saber o endereço de **pont2 dá erro.

A minha confusão é que mesmo não inicializando o *pont ele devolve o endereço dele. Não devia funcionar da mesma maneira para **pont2? Ou é que apesar de ele ser declarado, é declarado como um ponteiro para ponteriro e como não sabe o que é o *pont2, não consegue imprimir o endereço de memória do **pont2?

que complicação 😉

Link to comment
Share on other sites

Cada objecto (cada variavel) tem duas "partes": o valor propriamente dito e o espaco de memoria que ocupa (e o tipo como terceira parte).

Voltando as caixas ... ao fazeres

int num;

foste buscar uma caixa azul mas nao meteste nada la dentro.

Ao fazeres

int *pont;

foste buscar uma caixa verde mas nao meteste nenhuma ligacao la dentro.

A caixa existe, podes usa-la. Mes neste momento nao tem ligacao para nada relevante.

Se vais seguir a ligacao nunca se sabe o que pode acontecer.

No teu exemplo acima, por azar, nao deu erro (e deu-te a impressao que era valido), mas isso nao é garantido.

No codigo

int **pont2;

foste buscar uma caixa vermelha mas nao meteste nenhuma ligacao la dentro.

Se quiseres seguir a ligacao para uma caixa verde corres exactamente o mesmo risco do exemplo acima: ou seja, pode funcionar e dar-te a impressao que é valido.

Por sorte, no teu exemplo nao funcionou.

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.