Jump to content

Não percebo o que são ponteiros


hristosax
 Share

Recommended Posts

Queria dizer "tens de dar" 😄

Vou dar um exemplo.

Se quiseres definir uma função que tem como argumento uma variável (e não o seu valor) e a coloca com o valor 0 usas o seguinte código:

void zero(int* n) {
  *n = 0;
}

Para fazer isto precisas do ponteiro que indique qual a variável que queres alterar, porque de outra forma a única coisa a que tinhas acesso dentro da função era o valor da variável (irrelevante neste contexto).

Link to comment
Share on other sites

Queria dizer "tens de dar" 😄

Vou dar um exemplo.

Se quiseres definir uma função que tem como argumento uma variável (e não o seu valor) e a coloca com o valor 0 usas o seguinte código:

void zero(int* n) {
  *n = 0;
}

Para fazer isto precisas do ponteiro que indique qual a variável que queres alterar, porque de outra forma a única coisa a que tinhas acesso dentro da função era o valor da variável (irrelevante neste contexto).

acho que já estou a perceber...

hmmm..

Mesmo nao tendo aprendido funçoes, acho que estou a começar a perceber 🙂

Link to comment
Share on other sites

ponteiro é em Brasileiro, em Português diz-se apontador  😛

Como o nome indica um apontador é algo que aponta para outra coisa neste caso (programação) um apontador é uma variavel em que o seu valor é um endereço de memória para outra

imagina que tens este pedaço de código

char x = 50;

char *pX = &x;

*px = 55;

agora supoe que a variavel x é colocada pelo gestor de memoria do teu os no endereço 0x00FF, o seu conteudo (valor) é posto a 50

agora imagina que o apontador px (k não é nada mais k uma variável)

é colocado no endereço 0x0100 e o seu valor no exemplo acima é initializado para ser o endereço da variavel x ou seja 0x00FF.

na 3º linha de código *px = 55;

o * atrás da variavel px é o operador de indirecção e basicamente o operador faz isto "vê qual o valor que px contem, que é 0x00FF acede á posição de memoria 0x00FF e altera o conteudo dessa mesma posiçao para o valor 55"

visuamente antes da 3º linha de código tens

|----------|

|    50    |  0x00FF

|----------|

| 0x00FF|  0x0100

|----------|

PS: espero que tenha sido clara a explicação o melhor mesmo se ainda te restarem duvidas é ires a  http://en.wikipedia.org/wiki/Pointer_(computing)

Link to comment
Share on other sites

ponteiro é em Brasileiro, em Português diz-se apontador  😛

Como o nome indica um apontador é algo que aponta para outra coisa neste caso (programação) um apontador é uma variavel em que o seu valor é um endereço de memória para outra

imagina que tens este pedaço de código

char x = 50;

char *pX = &x;

*px = 55;

agora supoe que a variavel x é colocada pelo gestor de memoria do teu os no endereço 0x00FF, o seu conteudo (valor) é posto a 50

agora imagina que o apontador px (k não é nada mais k uma variável)

é colocado no endereço 0x0100 e o seu valor no exemplo acima é initializado para ser o endereço da variavel x ou seja 0x00FF.

na 3º linha de código *px = 55;

o * atrás da variavel px é o operador de indirecção e basicamente o operador faz isto "vê qual o valor que px contem, que é 0x00FF acede á posição de memoria 0x00FF e altera o conteudo dessa mesma posiçao para o valor 55"

visuamente antes da 3º linha de código tens

|----------|

|    50    |  0x00FF

|----------|

| 0x00FF|  0x0100

|----------|

PS: espero que tenha sido clara a explicação o melhor mesmo se ainda te restarem duvidas é ires a  http://en.wikipedia.org/wiki/Pointer_(computing)

Eu percebo o que é, mas não percebo como USÁ-lo...

Link to comment
Share on other sites

Ponteiros são muito mais usados em C, até porque não tens a vantagem da STL e portanto tens que implementar uma série de coisas.

À partida o teu programa só usa a memória que está definida em tempo de compilação. Por exemplo, se queres ter um array de inteiros, tens que definir qual o seu tamanho no código e não o podes alterar durante o programa.

int numeros[100];

Imagina agora que querias ter "uma espécie de array" mas em que pudesses alterar o seu tamanho e até inserir elementos no meio do array com facilidade. Para isso terias que usar dois conceitos de C: a estrutura e a alocação de memória dinâmica. Precisavas de uma estrutura com 2 elementos: um inteiro, e um apontador para a estrutura que representa o próximo elemento.

typedef struct list *lista;

struct list {
    int num;
    lista seguinte;
};

A isto se chama uma lista ligada. Repara que o tipo "lista" é um apontador para aquela estrutura. Para criar uma lista com um elemento que vale 30 fazes:

lista l = (lista)malloc(sizeof(struct list)); //Alocar memória durante a execução do programa
l -> num = 30;
l -> seguinte = NULL;

Em que o NULL significa que o apontador não aponta para nada (porque ainda não existe um elemento seguinte). É possível criar código para adicionar um elemento a uma lista no fim:

lista acrescenta(lista ll, int n) {
     lista iter = ll;
     while( iter -> seguinte != NULL) //enquanto existir um elemento a seguir
          iter = iter -> seguinte;
     iter -> seguinte = (lista) malloc(sizeof(struct list)); // alocar memória para o novo elemento
     iter -> seguinte -> num = n; //colocar o número no elemento que acabámos de criar
     iter -> seguinte -> seguinte = NULL; //assinalar o fim da lista
     return ll; //Repara que devolvemos o apontador que recebemos, porque o início da lista continua a ser o mesmo
}

E se quisermos, por exemplo, acrescentar um elemento no início da lista?

lista add_inicio(lista ll, int n) {
     novo = (lista) malloc(sizeof(struct list));
     novo -> num = n;
     novo -> seguinte = ll; //O elemento que vem a seguir ao que acrescentámos é primeiro da lista que recebemos
     return novo; //Devolvemos o elemento criado que é agora o primeiro elemento da nova lista
}

De forma igualmente simples podes, por exemplo, retirar um elemento do meio da lista, bastando para isso alterar o apontador "seguinte" do elemento que está antes dele para que passe a apontar para o elemento que vem a seguir. (E cuidado que é também necessário libertar a memória do elemento que retiramos)

Não respondo a dúvidas por mensagem.

Link to comment
Share on other sites

À partida o teu programa só usa a memória que está definida em tempo de compilação. Por exemplo, se queres ter um array de inteiros, tens que definir qual o seu tamanho no código e não o podes alterar durante o programa.

Em C já é possível criar arrays com um tamanho definido em run time: http://en.wikipedia.org/wiki/Variable-length_array

Link to comment
Share on other sites

Ponteiros são muito mais usados em C, até porque não tens a vantagem da STL e portanto tens que implementar uma série de coisas.

À partida o teu programa só usa a memória que está definida em tempo de compilação. Por exemplo, se queres ter um array de inteiros, tens que definir qual o seu tamanho no código e não o podes alterar durante o programa.

int numeros[100];

Imagina agora que querias ter "uma espécie de array" mas em que pudesses alterar o seu tamanho e até inserir elementos no meio do array com facilidade. Para isso terias que usar dois conceitos de C: a estrutura e a alocação de memória dinâmica. Precisavas de uma estrutura com 2 elementos: um inteiro, e um apontador para a estrutura que representa o próximo elemento.

typedef struct list *lista;

struct list {
    int num;
    lista seguinte;
};

A isto se chama uma lista ligada. Repara que o tipo "lista" é um apontador para aquela estrutura. Para criar uma lista com um elemento que vale 30 fazes:

lista l = (lista)malloc(sizeof(struct list)); //Alocar memória durante a execução do programa
l -> num = 30;
l -> seguinte = NULL;

Em que o NULL significa que o apontador não aponta para nada (porque ainda não existe um elemento seguinte). É possível criar código para adicionar um elemento a uma lista no fim:

lista acrescenta(lista ll, int n) {
     lista iter = ll;
     while( iter -> seguinte != NULL) //enquanto existir um elemento a seguir
          iter = iter -> seguinte;
     iter -> seguinte = (lista) malloc(sizeof(struct list)); // alocar memória para o novo elemento
     iter -> seguinte -> num = n; //colocar o número no elemento que acabámos de criar
     iter -> seguinte -> seguinte = NULL; //assinalar o fim da lista
     return ll; //Repara que devolvemos o apontador que recebemos, porque o início da lista continua a ser o mesmo
}

E se quisermos, por exemplo, acrescentar um elemento no início da lista?

lista add_inicio(lista ll, int n) {
     novo = (lista) malloc(sizeof(struct list));
     novo -> num = n;
     novo -> seguinte = ll; //O elemento que vem a seguir ao que acrescentámos é primeiro da lista que recebemos
     return novo; //Devolvemos o elemento criado que é agora o primeiro elemento da nova lista
}

De forma igualmente simples podes, por exemplo, retirar um elemento do meio da lista, bastando para isso alterar o apontador "seguinte" do elemento que está antes dele para que passe a apontar para o elemento que vem a seguir. (E cuidado que é também necessário libertar a memória do elemento que retiramos)

Acontece que não percebo quase nada do que puseste, ainda não sou tão avançado.

Sei o que são arrays, mas porque é que é que se tem de por um elemento com um POnteiro, e não simplesmente uma variável?!

Link to comment
Share on other sites

Vou tentar explicar sem código.

Porque em C toda a memória que tu utilizas está definida à partida. Se queres acrescentar coisas a meio, tens que fazer alocação dinâmica de memória. Isso corresponde a "pedir" para que o sistema te "arranje" mais memória para o que precisas.

Podes encarar a memória como sendo um array muito grande com milhões de posições. Quando pedes para arranjar um bloco de memória com um tamanho x, o sistema vai à procura de um local na memória que tenha esse espaço "vago", e devolve-te a posição onde começa esse bloco. Essa posição é um endereço de memória, que é o que fica guardado no ponteiro.

Não respondo a dúvidas por mensagem.

Link to comment
Share on other sites

Vou tentar explicar sem código.

Porque em C toda a memória que tu utilizas está definida à partida. Se queres acrescentar coisas a meio, tens que fazer alocação dinâmica de memória. Isso corresponde a "pedir" para que o sistema te "arranje" mais memória para o que precisas.

Podes encarar a memória como sendo um array muito grande com milhões de posições. Quando pedes para arranjar um bloco de memória com um tamanho x, o sistema vai à procura de um local na memória que tenha esse espaço "vago", e devolve-te a posição onde começa esse bloco. Essa posição é um endereço de memória, que é o que fica guardado no ponteiro.

Então estás a falar do apontador como sendo o Endereço de memória e não a variável que lá vai?

Não percebo então porque precisas de um apontador para um lugar de uma array, se podes indicar esse lugar SOZINHO.

Por exemplo, para que é que precisas de dar o nome de "Golden Spot" ao lugar de estacionamento nº12, se podes simplesmente chamá-lo de "lugar de estacionamento nº 12"?

A mesma pergunta com as variáveis.

Precisas de chamar ao Sr. Mota "O empresário da rua 20" se podes chama-lo de Sr mota?

Eu sei que sou teimoso..

Link to comment
Share on other sites

Há uma diferença. As variáveis que tu declaras no teu programa também têm endereços (i.e. estão numa determinada posição da memória). Os apontadores referem-se a esses endereços de memória. Sempre que precisares de te referir a alguma coisa que possa estar em locais diferentes da memória tens que usar apontadores. Para experimentar podes fazer isto:

#include <stdio.h>
main()  {
   int a=10;
   int *apontador=&a; // &variavel, devolve o endereço de memória de uma variável
   printf("Valor de a: %d\n", a);
   printf("Endereço de a: %d\n", &a);
   printf("Valor do apontador: %d\n", apontador);
   printf("Endereço do apontador: %d\n", &apontador);
   printf("Valor na memória apontada pelo apontador: %d\n", *apontador);

Não respondo a dúvidas por mensagem.

Link to comment
Share on other sites

Há uma diferença. As variáveis que tu declaras no teu programa também têm endereços (i.e. estão numa determinada posição da memória). Os apontadores referem-se a esses endereços de memória. Sempre que precisares de te referir a alguma coisa que possa estar em locais diferentes da memória tens que usar apontadores. Para experimentar podes fazer isto:

#include <stdio.h>
main()  {
   int a=10;
   int *apontador=&a; // &variavel, devolve o endereço de memória de uma variável
   printf("Valor de a: %d\n", a);
   printf("Endereço de a: %d\n", &a);
   printf("Valor do apontador: %d\n", apontador);
   printf("Endereço do apontador: %d\n", &apontador);
   printf("Valor na memória apontada pelo apontador: %d\n", *apontador);

Ahh então estás a dizer que eu me posso usar o ponteiro para mudar ESSE endereço de memória, e que não posso fazer isso com a variável?

Então o ponteiro dá-me o poder de mudar o endereço de memória de int a, em vez de só ter acesso à variável?

Mas para que é que eu precisaria disso ? 😛

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.