Escolar Documentos
Profissional Documentos
Cultura Documentos
Vetores - Ponteiros e Ref
Vetores - Ponteiros e Ref
21
declara a como um vetor de cinco objetos de dado inteiro; isto , como uma srie de cinco locaes de memria,
cada uma capaz de armazenar um valor do tipo inteiro.
Pode-se inicializar um vetor quando este declarado listando os valores iniciais para os seus elementos,
da seguinte maneira:
int a[5] = {75, 25, 100, -45, 60};
Neste caso, se o nmero de valores iniciais fornecido menor que o nmero de elementos do vetor, os
elementos restantes so inicializados com zero. Assim,
int b[5] = {75, 25};
equivalente a
int b[5] = {75, 25, 0, 0, 0};
Se no for especificado o nmero de elementos para um vetor inicializado, o nmero de valores iniciais
fornecidos determina o nmero de elementos. Assim,
int c[ ] = {75, 25, 100, -45, 60};
Para guardar valores em variveis ponteiro, deve-se utilizar o "operador de endereo" "&" frente de uma
varivel e para ler o contedo que um ponteiro indica deve-se utilizar o operador unrio "*" frente do ponteiro.
Em resumo [9]:
22
<ponteiro> = &<variavel>;
*<ponteiro> = <variavel>;
O tipo essencial para a utilizao de objetos de dados designados pelo endereo. O endereo
simplesmente d a posio de memria inicial que contm o objeto de dado. O tipo determina o tamanho do
objeto de dado, e as funes e operadores que podem ser aplicados a ele. Assim, no se tem apenas um nico
tipo de ponteiro para todos os endereos. Tem-se um tipo de "ponteiro-para-int" para enderear objetos de dados
inteiros, um tipo "ponteiro-para-double" para enderear objetos de dados double e assim por diante.
O operador unrio "*" chamado de "operador indireto", uma vez que ele permite que um objeto de dado
seja referenciado indiretamente, atravs de um identificador nomeando uma varivel ponteiro, ao invs de
diretamente, atravs de um identificador nomeando o prprio objeto de dado. O termo ponteiro aplicado tanto a
variveis ponteiro como aos endereos que elas contm; o contexto no qual a palavra usada determina quando
significa uma varivel ponteiro ou um valor de ponteiro (endereo).
A seguir so apresentado alguns exemplos de declaraes de variveis ponteiros:
int *p;
int *p, *r, *s;
double *q;
// ou int* p;
// ou double* q;
Neste caso, "p" um ponteiro para um inteiro e "q" um ponteiro para um double.
Para os ponteiros serem usados efetivamente, necessrio operadores e expresses que iro fornecer
os endereos correntes dos objetos de dados. Tal operador o "operador de endereo" representado por "&",
que retorna um ponteiro para um objeto designado. Assim, por exemplo, se "cont" uma varivel inteira, "&cont"
um ponteiro que aponta para "cont" e possui o tipo "ponteiro-para-int". Pode-se usar o endereo de um
operador para inicializar e atribuir valores para variveis ponteiro. Por exemplo, depois da declarao
int n;
int* p = &n;
a varivel ponteiro "p" aponta para varivel inteira "n". Alm disso, "*p" um nome alternativo para "n". Uma
atribuio a "*p" ir alterar o valor de "n", assim como uma atribuio a "n" ir alterar o valor de "*p".
Tambm pode-se fazer com que "*p" seja um nome alternativo para outra varivel, simplesmente
atribuindo outro valor a "p". Considerando que "m" seja uma varivel do tipo inteira, ento
p = &m;
ser executado, "i" ter o valor de "j", e "j" ter o valor anterior de "i". Em C e C++ argumentos so passados por
valor somente se os valores atuais dos argumentos so apenas transmitidos para a funo.
Por outro lado, ponteiros so valores e podem ser passados para funes. Se forem passados os
ponteiros para a funo "swap", esta poder us-los para acessar as variveis e trocar seus valores. Assim,
declara-se "swap()" para ter dois "ponteiro-para-int" como argumentos:
void swap (int* p, int* q);
Quando chama-se a funo, deve-se passar para ela ponteiros para as variveis cujos valores deseja-se trocar.
Pode-se fazer isso com a ajuda do operador de endereo. O comando
swap (&i, &j);
chama a funo e passa os endereos de "i" e "j" como argumentos. A definio de "swap" apresentada a
seguir.
void swap (int* p, int* q) {
int temp = *p;
*p = *q;
*q = temp;
// salva o valor de p
// atribui q para p
// q recebe valor inicial de p
23
Variveis passadas para a funo desta maneira so chamadas de variveis passadas por referncia,
porque referncias para as variveis (isto , ponteiros para elas) so passadas ao invs de valores de variveis.
Ponteiros tambm podem ser usados para "apontar" para estruturas. Por exemplo:
struct date {
int day;
int month;
int year;
}
date dt;
// varivel dt
date* pdt = &dt;
// ponteiro para dt
Neste caso, pode-se referir aos membros da varivel "dt" diretamente, da seguinte maneira: "dt.day",
"dt.month" e "dt.year". Tambm pode-se referir aos membros da varivel indiretamente, atravs do ponteiro "pdt":
"(*pdt).day", "(*pdt).month", "(*pdt).year". Os parnteses so necessrios porque o operador "." tem maior
precedncia. Como estas expresses ocorrem freqentemente, C++ fornece um operador de acesso indireto, ">", para simplific-las. Assim, a expresso "pdt->day" equivalente a "(*pdt).day" [3].
Torna-se interessante comentar que o C++ acrescentou algumas caractersticas sintaxe de ponteiros.
Basicamente, foi acrescentado o tipo void para ponteiros e ampliado o conceito const, associando-o aos
ponteiros. Para declarar um ponteiro void, a sintaxe a mesma da declarao de qualquer tipo, ou seja, o tipo
seguido do operador "*":
void * <nome_ponteiro>;
Exemplo:
void * ptr;
A diferena para os demais ponteiros est no fato de que o ponteiro void pode apontar para qualquer tipo de
dados, inclusive o NULL. O C++ permite que se acesse o contedo apontado por um ponteiro genrico somente
aps ele ser formatado, isto , eles no podem ser referenciados sem um casting explcito, porque o compilador
no pode determinar o tamanho do objeto para o qual ele est apontando. No entanto, pode-se atribuir outros
ponteiros a um ponteiro void ou atribuir o valor dele a um ponteiro comum. A motivao para a criao de
ponteiros void est no fato de se poder especificar funes de propsito geral cujo parmetro um ponteiro a
formatar em tempo de execuo. Baseando-se em critrios internos da funo (provavelmente um flag
especificando o tipo), este ponteiro pode ser modelado, de modo a apontar para o tipo adequado. Exemplo:
void Imprime (void *ptr, int flag);
void main () {
int inteiro = 10;
float real = 5.5;
Imprime (&inteiro, 1);
Imprime (&real, 2);
}
void Imprime (void *ptr, int flag) {
float soma = 22.2;
switch (flag) {
case 1: cout << "Numero Inteiro = " << (* (int *) ptr) << "\n";
break;
case 2: cout << "Numero Real = " << (* (float *) ptr) << "\n";
}
ptr = &soma;
cout << "Conteudo do ponteiro = " << (* (float *) ptr) << "\n";
* (float *) ptr = 22.2 + soma;
cout << "Conteudo do ponteiro = " << (* (float *) ptr) << "\n";
}
Em C++ pode-se definir ponteiros para constantes (apontadores cujo contedo imutvel), ponteiros
constantes (apontadores que no mudam o endereo apontado) e ponteiros constantes para valores constantes.
O primeiro tipo usado quando deseja-se que o contedo de um ponteiro fique inaltervel durante o
processamento de um programa. Neste caso utiliza-se a seguinte sintaxe:
const <tipo_a_apontar> * <nome_ponteiro>;
Exemplo:
const char *string = "Eu sou uma constante!";
24
Exemplo:
char * const msg = "Meu pontero eh constante!";
Neste caso, a string "Meu ponteiro eh constante!" pode ser modificada, mas qualquer nova frase colocada sobre
ela ter sempre o ponteiro "msg" a indic-la. O compilador no permitir que se aponte "msg" para outro local de
memria, mesmo que l esteja um char.
Tambm possvel desejar-se a total segurana de determinados dados declarando seu valor como
constante e ajustando um ponteiro constante para o endereo onde estar esse valor. Para tal, utiliza-se ponteiro
constante para constante atravs da seguinte sintaxe:
const <tipo_a_apontar> *const <nome_ponteiro>;
Exemplo:
const char * const msg = "Todos somos constantes!";
Quando tanto o ponteiro quanto o valor apontado so constantes, o compilador "congela" ambos e no permite
nem modificaes no contedo do ponteiro, nem no local de memria para o qual ele aponta. No exemplo, a
string "Todos somos constantes!" inaltervel e ser sempre encontrada pelo igualmente imutvel ponteiro
"msg" [9].
Uma referncia consiste em um apelido (alias) de uma varivel, ou seja, apesar de possurem nomes
distintos, uma referncia e sua varivel de inicializao ocupam o mesmo endereo de memria. A modificao
de uma afeta a outra. A principal utilidade de uma referncia melhorar a sintaxe de manipulao de parmetros
por referncia. A sintaxe de declarao de referncia a seguinte:
<tipo> &refer = var;
onde a referncia "refer" constitui uma segunda forma de chamar a varivel "var". Por exemplo, "int &" um tipo
"referncia-para-int", "double &" um tipo "referncia-para-double", e assim por diante. Como regra geral, uma
referncia deve ser sempre inicializada na sua declarao, depois ela serve como outro nome para aquele objeto
de dado. Por exemplo, suponha a declarao de uma varivel inteira "n":
int n = 10;
Tanto "n" quanto "r" designam o mesmo objeto de dado, que pode ser referenciado pelos dois "nomes". Assim, a
atribuio "n = 20;" altera o valor de "r" e "n" para 20, da mesma maneira que "r = 15;" altera o valor de "r" e "n" para
15.
interessante observar que a inicializao e a atribuio so completamente diferentes para referncias.
A inicializao estabelece uma correspondncia entre a referncia e objeto de dado. A atribuio, que igual
para referncia e outra varivel/valor, somente atribui um novo valor para um determinado objeto de dado.
Tambm deve-se ter em mente que uma referncia no uma cpia nem um ponteiro para uma varivel. Tratase da prpria varivel com um nome diferente. A principal vantagem mesmo a passagem de parmetros por
referncia (seo 8), da, inclusive, o nome deste tipo de varivel [3, 9].