Ponteiros em C
Ponteiros em C
Um ponteiro é uma variável que contem o endereço de uma variável.
O operador & fornece o endereço de uma variável. Por exemplo, de c é um char e p é um ponteiro,
p=&c
atribui a p o endereço da variável c. Diz-se, portanto, que "p aponta para c".
O operador * quando aplicado a um ponteiro acessa o objeto apontado por ele. Por exemplo, suponha que x e y são inteiros e ip é um ponteiro para int. A sequência abaixo mostra como usar & and *[1]:
int x=1, y=2;
int *ip; /* ip é um ponteiro para int */
ip = &x; /* ip agora aponta para x */
y = *ip; /* y agora é 1 */
*ip = 0; /* x agora é 0 */
Na declaração de variáveis ponteiro, cada ponteiro aponta para o tipo de dado declarado, se comportando como tal.
Por exemplo, se ip aponta para o inteiro x, então *ip pode ocorrer no contexto que x ocorre, portanto,
*ip = *ip + 10; /*Incrementa *ip de 10 (ou incrementa x de 10)*/
y = *ip + 1 /*pega o que ip aponta e soma 1 e atribui a y*/
*ip += 1 /*Incrementa *ip de 1*/
- Exibindo o endereço de uma variável
- Programa exemplo para exibir o endereço de uma variável:
#include <stdio.h>
int main()
{
char letra = 's';
int numero = 35;
printf("Exibindo o endereço de memória de variáveis:\n\n");
printf("Variável letra = %c, endereço = %p\n",letra, &letra);
printf("Variável numero = %d, endereço = %p\n",numero,&numero);
}
Ponteiros e argumentos de funções
A linguagem C passa argumentos para funções por valor. Portanto, não há como acessar diretamente as variáveis usadas para chamar a função. Para acessar em uma função as variáveis fornecidas como argumentos deve-se utilizar ponteiros, que apontam para as variáveis.
- Exemplo 1
- Função que modifica uma variável do programa principal, recebendo argumentos por referência através de um ponteiro[2]:
#include <stdio.h>
void Func(int *y); /*Protótipo da função*/
void main () /*Programa principal para teste*/
{
int x=15;
printf("Primeiro valor de x=%d\n", x);
Func(&x);
printf("Segundo valor de x=%d\n", x);
}
void Func(int *y) /*Definição da função*/
{
++*y;
printf("Valor de y=%d\n", *y);
} // fim Func
- Veja a diferença com uma função que recebe argumento por valor:
#include <stdio.h>
void Func(int y); /*Protótipo da função*/
void main () /*Programa principal para teste*/
{
int x=15;
printf("Primeiro valor de x=%d\n", x);
Func(x);
printf("Segundo valor de x=%d\n", x);
}
void Func(int y) /*Definição da função*/
{
++y;
printf("Valor de y=%d\n", y);
} // fim Func
- Exemplo 2
- Função Swap que faz intercâmbio do valor de duas variáveis[1]:
#include <stdio.h>
void Swap(int *px, int *py); /*Protótipo da função*/
void main () /*Programa principal para teste*/
{
int a=1, b=2;
printf("Valor de a=%d, valor de b=%d\n", a, b);
Swap(&a, &b);
printf("Valor de a=%d, valor de b=%d\n", a, b);
}
void Swap(int *px, int *py) /*Definição da função*/
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
Como o operador & fornece o endereço da variável, &a aponta para a. Na função Swap os parâmetros devem ser declarados como ponteiros e os argumentos são acessados por eles.
Ponteiros e vetores
Há uma forte relação entre ponteiros e vetores.
Na linguagem C uma variável vetor é implementada como uma variável ponteiro.
Quando declaramos um vetor, por exemplo:
int v[10];
a variável v é "um ponteiro para int", ou int *v. Não aparece um asterisco na declaração porque os colchetes indicam automaticamente que a variável é um ponteiro. A diferença entre as declarações int *v; e int v[10]; é que a última reserva 10 posições de inteiros começando na posição v[0][2].
A variável v guarda o endereço base do vetor, que é o endereço do dado armazenado na posição v[0] do vetor. Isto é equivalente a definir um ponteiro, por exemplo pv e atribuir a ele o endereço de v[0]:
pv=&v[0];
//A expressão acima é equivalente a:
pv=v;
//uma vez que v guarda o endereço inicial do vetor,
Quando incrementamos um ponteiro ele passa a apontar para o próximo valor do mesmo tipo para o qual o ponteiro aponta. Se você incrementa um ponteiro char* ele anda 1 byte na memória, se você incrementa um ponteiro int* ele anda 2 bytes na memória.
No caso de vetores, pode-se acesssar os valores dos dados armazenados no vetor utilizando ponteiros.
- Equivalência entre índices de vetores e ponteiros
- Suponha que você defina uma variável i como índice para acessar os valores em um vetor v, logo:
v[i]
- é equivalente a utilizar o ponteiro
*(v + i)
- Exemplo:
#include <stdio.h>
void main ()
{
int v[10]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
printf("O terceiro elemento do vetor é: %d\n", v[2]);
printf("O quarto elemento do vetor é: %d\n", *(v+3));
}
- Diferença entre o nome de um vetor e um ponteiro
- Um ponteiro é uma variável, por exemplo, se pv é um ponteiro e v é um vetor, pv=v e pv++ são operações válidas. Entretanto, o nome do vetor não é uma variável, portanto, a operação v++ é ilegal.
Vetores como parâmetros de funções
Todo parâmetro deve ser declarado dentro de uma função. Entretanto, a faixa valores de um parâmetro vetor somente é declarada no programa principal (ou chamador da função) [2]. Isto ocorre porque o C não aloca novamente memória para o parâmetro, usando o vetor original do programa principal.
- Exemplo de vetor como parâmetro
- Função que calcula a média dos valores de um vetor.
#include <stdio.h>
#define TAM 5
int Media(vetor, tamanho)
float vetor[]; //Note que não é declarada a faixa de valores do vetor.
int tamanho;
{
int i;
float soma = 0;
for (i=0; i < tamanho; i++)
soma += vetor[i];
return (soma / tamanho);
}
void main ()
{
float Med;
float v[TAM]={1.0, 2.0, 3.0, 4.0, 5.0};
Med = Media(v, TAM);
printf("Média do vetor: %f\n", Med);
}
Vetores como argumentos por referência para funções
Como uma variável vetor é um ponteiro os argumentos vetores são passados por referência para funções, e não por valor como variáveis simples. O que é passado para a função é o endereço base do vetor.
- Exemplo de vetor como argumento por referência
#include <stdio.h>
#define TAM 5
void Func(vetor, tamanho)
int *vetor; //Esta declaração é equivalente a int vetor[];
int tamanho;
{
int i;
for (i=0; i < tamanho; i++)
vetor[i]=99;
}
void main ()
{
int i;
int v[TAM]={1, 2, 3, 4, 5};
for (i=0; i < TAM; i++)
printf("Vetor1[%d]= %d\n", i, v[i]);
Func(v, TAM);
for (i=0; i < TAM; i++)
printf("Vetor2[%d]= %d\n", i, v[i]);
}
- Note que a declaração formal do parâmetro vetor pode ser declarada de duas formas:
int *vetor;
- ou
int vetor[];
- as duas são equivalentes, mas a primeira é preferível por explicitar que a variável é um ponteiro.
Ponteiros e strings
Como os strings são vetores de caracteres, cujos caracteres podem ser acessados por índices, o uso de ponteiros com strings é equivalente ao uso de ponteiros com vetores.
Função Strlen com ponteiros
#include <stdio.h>
int Strlen(char *s);
void main ()
{
char c[50]="Brasil";
int len;
len = Strlen(c); /*Argumento é um ponteiro para a string c*/
printf("Comprimento da string: %d\n", len);
}
int Strlen(char *s)
{
int i;
for (i=0; *s != '\0'; s++)
i++;
return (i);
}
- Note que o ponteiro para a string c (equivalente a &c[0]) é passado como argumento para a função Strlen, a qual é copiada para o parâmetro *s. Portanto, internamente a função é possível incrementar a variável ponteiro s com s++.
- Compare com a função Strlen sem ponteiros vista no estudo de Strings.
Função Strcat com poteiros
Recebe duas strings como parâmetros e concatena as strings na primeira.
#include <stdio.h>
void Strcat(char *s1, char *s2);
void main ()
{
char string1[20]="Brasil", string2[20]="2014";
Strcat(string1, string2); /*Os argumentos são ponteiros para as strings*/
printf("Strings concatenadas: %s\n", string1);
}
void Strcat(char *s1, char *s2)
{
for (; *s1 != '\0'; s1++)
;
for (; *s2 != '\0'; s1++, s2++)
*s1=*s2;
}
- Detalhe do funcionamento da função:
- O segundo for poderia ser escrito da forma:
for (; *s2 != '\0'; *s1++=*s2++) ;
- neste caso, o valor apontado por s1 é primeiro igualado ao apontado por s2 e depois os ponteiros s1 e s2 são incrementados.
- Compare com a função Strcat sem ponteiros vista no estudo de Strings.
Veja referência interessante sobre ponteiros[3].
Referências
- ↑ 1,0 1,1 KERNIGHAN, B.W.; RITCHIE, D.M. The C Programming Language, Prentice Hall, 2o ed. 1978.
- ↑ 2,0 2,1 2,2 TENENBAUM, Aaron M.; LANGSAM, Yedidyah; AUGENSTEIN, Moshe. Estruturas de dados usando C. Makron Books, 1995.
- ↑ http://homepages.dcc.ufmg.br/~joaoreis/Site%20de%20tutoriais/c_int/ponteiros.htm
--Evandro.cantu (discussão) 12h44min de 29 de agosto de 2014 (BRT)