Ponteiros em C

De Wiki Cursos IFPR Foz
Ir para navegaçãoIr para pesquisar

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. 1,0 1,1 KERNIGHAN, B.W.; RITCHIE, D.M. The C Programming Language, Prentice Hall, 2o ed. 1978.
  2. 2,0 2,1 2,2 TENENBAUM, Aaron M.; LANGSAM, Yedidyah; AUGENSTEIN, Moshe. Estruturas de dados usando C. Makron Books, 1995.
  3. 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)