Você está na página 1de 4

Professora Isabel Harb Manssour Linguagem de Programao C++

21

6. VETORES, PONTEIROS E REFERNCIAS


possvel referir-se a objetos de dados pelos seus endereos ou seus nomes. Nesta seo so mostrados meios mais flexveis de designar objetos de dados, o que envolve nomes, endereos e o relacionamento entre eles. Como em qualquer outra linguagem de programao um array ou vetor uma srie de objetos de dados, todos eles possuindo o mesmo tipo; estes objetos de dados so chamados de elementos do vetor. Um vetor declarado fornecendo-se o tipo dos seus elementos, o nome do vetor e o nmero de elementos. Por exemplo:
int a[5];

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};

declara um vetor de cinco elementos. Os elementos de um vetor so designados, considerando o exemplo anterior, por a[0], a[1], a[2], a[3] e a[4]. Os inteiros entre chaves so "ndices" e variam de zero at o nmero mximo de elementos do vetor menos um. Os ndices podem ser tanto expresses como constantes. Assim a[i+j] refere-se ao elemento designado pelo valor resultante da expresso i+j. Quando se trabalha com loops, expresses como c[i++] e c[i--] so freqentemente usadas. Neste caso, depois do valor corrente de i ser usado como ndice, o valor de i incrementado ou decrementado. Assim, na prxima vez que i usado como ndice ele vai referir-se ao prximo elemento (para ++) ou ao elemento anterior (para --) do vetor [3]. Apesar dos programadores em geral reconhecerem nos ponteiros o principal ponto de dificuldade no aprendizado da linguagem, sua utilidade incontestvel. Com ponteiros o programador pode otimizar o gerenciamento da memria, reutilizando espaos alocados para variveis, compartilhando espao entre variveis e solicitando ou liberando memria dinamicamente. Alm disso, muitas aplicaes tm sua performance otimizada em termos de velocidade quando se usam ponteiros. Um ponteiro um endereo de um objeto de dado de um tipo particular. Em outras palavras, ponteiros nada mais so do que variveis cujos valores so endereos de memria. A sintaxe de declarao de ponteiros a seguinte:
<tipo_variavel> * <nome_ponteiro>;

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]:

Professora Isabel Harb Manssour Linguagem de Programao C++


<ponteiro> = &<variavel>; *<ponteiro> = <variavel>;

22

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;

atribui o endereo de "m" a "p". Pode-se usar ponteiros para dar s funes acesso a variveis passadas como argumentos. Por exemplo, suponha que queira-se escrever uma funo que troque os valores de duas variveis inteiras. Assim, depois do comando
swap (i, j);

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

Professora Isabel Harb Manssour Linguagem de Programao C++

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!";

Professora Isabel Harb Manssour Linguagem de Programao C++

24

Ponteiros constantes so usados quando h interesse em que um determinado endereo de memria seja sempre localizado por um certo ponteiro, independente do valor nesse endereo. Nesses casos quem deve ser constante o ponteiro, e no seu contedo. A sintaxe para ponteiro constante a seguinte:
<tipo_a_apontar> *const <nome_ponteiro>;

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;

e a declarao da referncia "r" atravs de


int& r = n;

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].

Você também pode gostar