Ponteiros em C: mudanças entre as edições
Linha 85: | Linha 85: | ||
<syntaxhighlight lang="c"> | <syntaxhighlight lang="c"> | ||
pv=&v[0]; | pv=&v[0]; | ||
// | //A expressão acima é equivalente a: | ||
pv=v; | pv=v; | ||
//uma vez que v | //uma vez que v guarda o endereço inicial do vetor, | ||
</syntaxhighlight> | </syntaxhighlight> | ||
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 <tt>char*</tt> ele anda 1 byte na memória, se você incrementa um ponteiro <tt>int*</tt> ele anda 2 bytes na memória. | 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 <tt>char*</tt> ele anda 1 byte na memória, se você incrementa um ponteiro <tt>int*</tt> ele anda 2 bytes na memória. |
Edição das 13h30min de 29 de agosto de 2014
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*/
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[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 */
- 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
Todo parâmetro deve ser declarado dentro da 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 passado como argumento
- 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 != TAM; i++)
soma += vetor[i];
return (soma / TAM);
}
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);
}
Observe que, como uma variável vetor é um ponteiro, os argumentos vetores são passados por referência, e não por valor como variáveis simples.
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 &v[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++)
;
}
- Detalhe do funcionamento da função
- No segundo for o valor apontado por s1 é 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.
Exercícios com ponteiros e strings
- Construa uma função que receba como parâmetro um ponteiro para uma string e informe quantos caracteres 'a' tem o string.
Referências
--Evandro.cantu (discussão) 10h31min de 12 de junho de 2014 (BRT)