Para simplificar, um ponteiro é uma variável que armazena um endereço de memória, apontando para o mesmo. Todas as demais variáveis armazenam dados de algum dos tipos básicos da linguagem C. No entanto, um ponteiro indica um espaço de memória em particular que contem um endereço de memória.
A criação de um ponteiro é feita através da declaração de variáveis com o caracter * sucedido do nome da variável.
int *A;
Um ponteiro sempre aponta para o endereço de memória que contêm o tipo de dado usado na declaração do ponteiro. Assim, um ponteiro do tipo int somentepode apontar para um endereço que armazene um dado do tipo int;
Existem 2 operadores necessários relacionados a ponteiros:
Seguem alguns exemplos desses conceitos:
Uso do operador & int main(void){ int *pt, n; n = 10; pt = &n; printf("Valor de n = %d",n); printf("O endereço de n = %p",pt); return 0; } Uso do operador * int main(void){ int *pt, n; pt = &n; *pt = 10; printf("Valor de n = %d",n); printf("O endereço de n = %p",pt); return 0; }
De forma resumida, imagine que um ponteiro possui duas capacidades de armazenamento, onde ele pode armazenar o endereço de alguma variável e o seu valor. Diante disso, temos que um ponteiro dado por *p em conjunto com uma variável num, pode receber tanto o valor que esta variável suporta como o seu endereço. Para que seu endereço seja armazenado, é dado a variável do ponteiro recebendo o & (indicador de endereçamento na memória), ou seja, p = &num. Por outro lado, para que o ponteiro receba o valor da variável o ponteiro do ponteiro receberá a prórpria variável, ou seja, *p = num.
Atente-se que uma vez declarada uma variável, seu endereço é imutável (a menos que comandos sejam realizados com este objetivo), porém, ao alterar o valor desta variável, automaticamente o valor apontado pelo ponteiro, também é alterado. Da mesma forma que uma vez declaro um ponteiro para uma variável, se alterado o valor do ponteiro do ponteiro, o valor da própria variável também será alterado. Para que não fique confusa a explicação, segue abaixo um script que explica melhor os conceitos de ponteiro:
#include <stdio.h> #include <stdlib.h> #include <locale.h> /* Este programa, terá como objetivo a realização de testes em ponteiros, para observar e entender o comportamento dos mesmos na memória e exibição de seus dados enquanto programa. */ int main() { setlocale(LC_ALL,"portuguese"); int num,valor,valor2; int*p; num=55; p=# valor=*p; valor2=p; printf("\n\n Valor de num = %d",num); //Este é o valor que uma variável possui. Neste caso, a variável "num" com o valor "55". printf("\n\n Valor de p = %d",p); //A variável do ponteiro é o que recebe o endereço de um variável, ou seja, será um apontador para o endereço de memória //da variável. Neste caso, "p" é onde será armazenado o endereço de memória da variável "num". printf("\n\n Valor de *p = %d",*p); //O ponteiro em sí, funcionará como direcionador direto do valor de uma variável em que o endereço está armazenado, ou //seja, este será como um exibidor direto da variável apontada. Neste caso, "*p" receberá o valor "55", mesmo da //variável "num". printf("\n\n Valor de valorl = %d",valor); printf("\n\n Valor de valor2 = %d",valor2); printf("\n\n\n ======================= \n\n\n"); /* Dessa forma, foi observado que com um ponteiro, é possível obter tanto o endereço quanto o valor de uma variável X. Agora, teremos como objetivo o estudo da manipulação deste ponteiro, veremos se é possível alterar os valores e endereços de uma variável X através do ponteiro. */ //Situação I - Alterar o valor da variável e ver como o ponteiro se comporta printf("\n \\\ SITUAÇÃO I ///\n"); num=20; printf("\n\n Valor de num = %d",num); printf("\n\n Valor de p = %d",p); printf("\n\n Valor de *p = %d",*p); //Situação II - Alterar o valor do *p e ver como o restante se comporta printf("\n\n\n \\\ SITUAÇÃO II ///\n"); *p=125; printf("\n\n Valor de num = %d",num); printf("\n\n Valor de p = %d",p); printf("\n\n Valor de *p = %d",*p); printf("\n\n\n ======================= \n\n\n"); /* Ou seja, pode-se concluir que caso o usuário/programdor altere o valor da variável (situação I) o endereço de memória permanecerá o mesmo, porém o valor do ponteiro será igualado ao da variável. Da mesma forma que ao se alterar o valor do ponteiro (situação II), o valor da variável também é mudado, permanecento o endereço de memória imutável em qualquer situação. Portanto, alterar o valor do ponteiro, irá automaticamente alterar o valor da variável em que aquele ponteiro aponta! */ return 0; }
Existem 2 maneiras de realizar a passagem de parâmetros para uma função: por valor e referência. A linguagem C permite apenas passagem por valor. Entretanto, pode-se usar ponteiro para simular uma passagem por referência.
A passagem de parâmetros por valor, cria uma cópia de conteúdos para serem utilizados enquanto função. Logo, quando a execução termina, essas cópias são destruídas e suas mudanças destrídas (Após enviar os dados ao main principal).
Já a passagem de parâmetros por referência trabalha com o conteúdo orginal do main, sem a criação de cópias. Logo, quando a execução da função é finalizada, os valores ainda permanecem. Na linguagem C, isso deve se realizado por ponteiros, onde cópias de apenas os endereços de memória são feitas.
Segue um exemplo abaixo das duas situações, onde uma função é feita para gerar o triplo de 2 números:
1. Parâmetros por valores #include <stdio.h> void calculo(int x, int y); int main(void) { int x, y; x = 3; y = 5; calculo(x, y); getchar(); } void calculo(int x, int y) { x = x * 3; y = y * 3; println(“x = %d y = %d” , x, y); } -------------------- 2. Parâmetros por referência #include <stdio.h> void calculo(int *x, int *y); int main(void) { int x, y; x = 3; y = 5; calculo(&x, &y); println(“x = %d y = %d” , x, y); getchar(); } void calculo(int *x, int *y) { *x = *x * 3; *y = *y * 3; }
Arrays são diretamente ligadas a ponteiros, utilizar o nome de um array sem um subscrito informa o endereço da primeira posição do array, como no exemplo a seguir:
int a[5], *pt1, *pt2; pt1 = a; Isso faz o mesmo sentido quanto pt1 = &a[0];
A passagem de um arraypara uma função requer o uso de referência. Copiando apenas o endereço de memória ocupado pela primeira posição do array, segue um exemplo abaixo com tais concitos:
#include <stdio.h> void preenche(int* p); int main(void) { int v[3]; preenche(v); return 0; }